Excess properties in TypeScript
Properties defined on an object that are not expressed by the type of the object are called excess properties.
Here's an example:
type Person = {
firstName: string
}
const person: Person = {
firstName: "Filip",
lastName: "Tammergård", // ⛔️ Object literal may only specify known properties, and 'lastName' does not exist in type 'Person'.
}
In this case, TypeScript makes it clear that lastName
is not defined in the Person
type and is therefore not allowed.
However, in other cases, TypeScript does not check for excess properties:
type Person = {
firstName: string
}
const personDetails = {
lastName: "Tammergård",
}
const person: Person = {
firstName: "Filip",
...personDetails, // 👍 This is fine!
}
This is, to me, a pretty weird thing about TypeScript—but it is well documented in the docs.
Notice that is does not have to do with the spread syntax specifically, but rather that TypeScript does not run excess property checks on objects when they are defined separately.
Here's another example:
type Person = {
firstName: string
}
function printPerson(p: Person) {
console.log(p.firstName)
}
printPerson({
firstName: "Filip",
lastName: "Tammergård", // ⛔️ Object literal may only specify known properties, and 'lastName' does not exist in type 'Person'.
})
In this case, TypeScript errors on passing lastName
where it's not expressed in the function parameter type.
Let's assign the object to a variable and pass that to printPerson
instead:
type Person = {
firstName: string
}
function printPerson(p: Person) {
console.log(p.firstName)
}
const person = {
firstName: "Filip",
lastName: "Tammergård",
}
printPerson(person) // 👍 This is fine!
TypeScript being a structural type system means it checks minimum requirements rather than exact requirements—at least in some cases.
The reason TypeScript is doing excess property checks when passing an "inline" object is probably since it won't be used anywhere else and TypeScript can assume the excess property is a mistake.