Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript losing type information after spread? [duplicate]

Tags:

typescript

In the following code, why does the personInvalidAndErrorCaught assignment give a TypeScript error (as I would expect) but the personInvalidButErrorUncaught does not? Especially since both lines transpile to the same JavaScript?

TypeScript:

interface Person {
    name: string;
}
const person: Person = { name: "name" }
const personInvalidAndErrorCaught: Person = { ...person, invalidKey: ""  } // Error as expected: Object literal may only specify known properties, and 'invalidKey' does not exist in type 'Person'.(2322)
const personInvalidButErrorUncaught: Person = { ...person, ...{ invalidKey: "" } } // Why no error? Especially since this line transpiles to the same JS as the line above?

Transpiled JavaScript:

"use strict";
const person = { name: "name" };
const personInvalidButCaught = Object.assign(Object.assign({}, person), { invalidKey: "" }); 
const personInvalidButUncaught = Object.assign(Object.assign({}, person), { invalidKey: "" });

Image showing error:

Screenshot of playground showing error

Playground Link

like image 524
Heinrich Filter Avatar asked Nov 26 '25 03:11

Heinrich Filter


1 Answers

The difference is that you're directly assigning the object literal containing the invalid key in the case that doesn't work, and TypeScript treats that specially. From the beta documentation (they warn that link may rot):

Notice the given argument to createSquare is spelled colour instead of color. In plain JavaScript, this sort of thing fails silently.

You could argue that this program is correctly typed, since the width properties are compatible, there’s no color property present, and the extra colour property is insignificant.

However, TypeScript takes the stance that there’s probably a bug in this code. Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments.

(my emphasis)

(There's also the current documentation you found.)

In your second case where there's no error, you're not assigning the object literal with the excess property to the variable directly, you're assigning the wrapper object that it gets spread into. It's a subtle distinction, granted, but it's a distinction.

This is just a special case TypeScript flags up because when you're assigning the literal directly and specifying an invalid property, that's likely to be a bug. Something more complex may not be.

The fact that spreading doesn't trigger this check is, as you found in one of the tests, by design:

const a1: A = { ...extra1 }; // spread should not give excess property errors
like image 96
T.J. Crowder Avatar answered Nov 28 '25 17:11

T.J. Crowder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!