TypeScript's type system operates on a structural basis, allowing for structural subtyping. This means that object types are considered open and do not restrict additional unknown properties. They are not sealed or exact as discussed in microsoft/TypeScript#12936:
type A = { a: number }
const a2 = { a: 42, b: 43 };
const a3: A = a2; // no error
This feature supports extensions of interfaces and classes. Without it, forming type hierarchies like
interface X extends Y { extraProp: any }
or
class X extends Y { extraProp: any }
would be challenging to comprehend.
However, there are scenarios where the compiler might issue warnings regarding unexpected additional properties. The excess property checking introduced in microsoft/TypeScript#3823 triggers when an object literal is directly assigned to a non-empty target. When dealing with non-empty types like {a: number}
, assigning the object literal {a: 42, b: 43}
to a
results in a warning. Conversely, if the type is empty such as {}
, no warning is produced.
Prior to the implementation of the unknown
type, the usage of the empty object type {}
was widespread to denote "any non-nullish type whatsoever," prompting complaints from the compiler in such cases would lead to excessive warnings.
The excess property checking mechanism should be viewed more as a linter rule than a feature of the type system.
That sums up why this behavior occurs.
In response to your query about a type that only accepts objects with value {}
, the type system does not inherently prevent extra properties. There are complex workarounds like the one proposed in microsoft/TypeScript#12936 utilizing generics to constrain excess properties to the never
type but these can become convoluted.
In the case of {}
, an index signature with the value type never
can be employed to prohibit all properties:
type A = { [k: string]: never };
const a: A = { a: 42, b: 43 }; // error
const a2: A = { a: 42 }; // error
const a3: A = {}; // okay
The practical use case for such a type may not be readily apparent, and implementing it could pose challenges.
Playground link to code