-1

Why is this valid:

type A = {
    a: string;
};

function withA(a: A) {}

const test = (message: {b: number}) => {
    withA({
        ...message, // this
        a: 'foo',
    });
};

and this is valid:

type A = {
    a: string;
};

function withA(a: A) {}

const test = <T>(message: T) => {
    withA({
        ...message,
        b: 'bar', // this
        a: 'foo',
    });
};

I don't understand why using the spread operator makes this possible.

I tried reading documentation about structural typing and exact types but I can't find a precise answer.

Edit: My real question is why we have no warning here, like "Object literal may only specify known properties, and 'b' does not exist in type 'A'". If I remove the spread line I do have a warning

6
  • Could you also include what you think the result should be and why? It would help us identify your mis-understanding.
    – phuzi
    Commented Jul 10 at 9:26
  • Sorry maybe it wasn't clear enough. I don't understand why I have no warning here. Like "Object literal may only specify known properties, and 'b' does not exist in type 'A'"
    – Teebs
    Commented Jul 10 at 9:28
  • Are you expecting excess property checks? They only apply to a fairly narrow range of cases - your objects do satisfy the required interface.
    – jonrsharpe
    Commented Jul 10 at 9:29
  • If I remove the spread line then I have a warning, why?
    – Teebs
    Commented Jul 10 at 9:30
  • 1
    TS version? Compiler settings? I can't repro - there is an error for b: Playground Link
    – VLAZ
    Commented Jul 10 at 10:22

2 Answers 2

0

TypeScript uses structural type - meaning an object is the same type if it has at least the object type structure
so as log as you pass to type A an object that contains the property a: string - it will be valid
in both examples above you are passing a: string along with more fields.

  • this is regardless of the use of ... spread.

if you want type A to be more strict, you will have to define a custom type

-1

The spread syntax is not an operator. And I don't think it's relevant for your question:

You can always pass an object that has more properties than a function requires, you might as well add property x and y and the code would still compile. withA only requires the property a and it's part of the object literal in both cases, it is irrelevant which properties message contains. Even if a was part of message and had a different type, you are overwriting it again in your literal (because the property is defined after spreading message).

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.