Consider the following code
interface Config {
label?: string;
width?: number;
}
function printLabel(labelledObj: Config) {
console.log(labelledObj.label);
}
let myObj = {not_in_interface: 10, label: "Size 10 Object"};
// No error
printLabel(myObj);
// Will run into error Argument of type '{ not_in_interface: number; label: string; }' is not assignable to parameter of type 'Config'
printLabel({not_in_interface: 10, label: "Size 10 Object"});
What is the reason for the discrepancy?
It seems like anonymous object triggers excess property checking while named object does not.
TypeScript only checks for excess properties at the location an object literal is declared (as you stated in your question). The TypeScript docs describe this check: (Also feel free to check out the full spec here.)
TypeScript 1.6 enforces stricter object literal assignment checks for the purpose of catching excess or misspelled properties. Specifically, when a fresh object literal is assigned to a variable or passed as an argument for a non-empty target type, it is an error for the object literal to specify properties that don't exist in the target type.
So why this behavior? In short, in some use cases you'd want to allow extra properties when passing around objects, and in other use cases you wouldn't. For example, it'd be sad if our printWeightInPounds function below didn't accept our Dog object:
interface Animal { weight: number; }
interface Dog extends Animal { breed: string; }
const myDog: Dog = { weight: 100, breed: "Poodle" }; // a big poodle!
printWeightInPounds(myDog);
Being strict and not allowing extra properties in all cases would disallow a lot of legitimate code. However, opt-in strictness could be a good thing in some places. There are proposals to have an "Exact type" feature which would allow you to opt-in to only passing identical types around. It's still in discussion though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With