Structural Typing
TL;DR
TypeScript uses Structural Typing (often called “Duck Typing”). This means if two objects have the same shape (the same properties with the same types), TypeScript considers them to be the exact same type, even if they don’t explicitly implement the same interface.
“If it walks like a duck and quacks like a duck, it’s a duck.”
Mental Model
How It Works
In Nominal Typing (used in Java or C#), a class must explicitly state implements Point for the compiler to accept it as a Point.
In Structural Typing (TypeScript), the names of the types don’t matter. TypeScript only compares the structures. If an object possesses all the properties required by an interface, it is accepted. Having extra properties is perfectly fine (though object literals are checked more strictly).
Example
interface User {
id: number;
name: string;
}
function printUser(user: User) {
console.log(`${user.id}: ${user.name}`);
}
// This object does NOT explicitly implement the User interface
const adminData = {
id: 1,
name: "Alice",
role: "Admin", // Extra property
permissions: [1, 2, 3] // Extra property
};
// ...But it has 'id' (number) and 'name' (string).
// So TypeScript happily accepts it!
printUser(adminData);
Common Interview Questions
What is Excess Property Checking?
While structural typing allows extra properties, there is an exception: Object Literals. If you pass an object literal directly into a function, TypeScript will throw an error for extra properties to help catch typos.
// ERROR: Object literal may only specify known properties
printUser({ id: 2, name: "Bob", role: "User" });
// But if assigned to a variable first, it works (as seen in the main example).
Why did TypeScript choose Structural Typing over Nominal Typing?
JavaScript is an inherently dynamic and duck-typed language. Functions frequently accept any object as long as it has specific keys. Structural typing accurately models how JavaScript developers actually write code, allowing for flexible API consumption without forcing heavy class hierarchies.