TypeScript is structural, so a value with extra properties is assignable to a type that needs fewer. That would hide typos in options objects, so the handbook describes an extra rule: excess property checking. Object literals get special treatment when assigned to a variable or passed as an argument: if the literal has any property the target type doesn't have, it's an error.
The check applies only to a fresh object literal, the expression written at that spot. Storing it in a variable first, spreading it, or asserting it to a type removes freshness, and only ordinary structural assignability applies.
Two related rules to know:
- Weak types (TS 2.4). A type whose properties are all optional rejects anything that shares no properties with it, even from a variable.
{ colour: "red" }has nothing in common with{ color?: string; width?: number }, so this is an error without a literal at all. - Where the check does not apply. Spread members aren't checked, and a union target without a discriminant accepts a literal that matches any member. With a discriminant, TypeScript picks the matching member and checks against it.
Fixing it: correct the typo; if the extra property is legitimate, add it to the type, or add an index signature ([key: string]: unknown). The handbook says if you're hitting this on option bags, revise the declarations instead of silencing the check. An as Options assertion bypasses it but also hides real mistakes.
Neighbouring object-type features: ? makes a property optional (T | undefined when read); readonly blocks assignment at compile time only; an index signature declares a value type for unknown keys. exactOptionalPropertyTypes (TS 4.4, not in strict) distinguishes an absent property from one set to undefined.