Hint
Compatibility is based on shape, not name — if it has the right properties, it is the right type
TypeScript uses structural typing: two types are compatible if they share the same shape (property names and types), regardless of their declared names. This is unlike nominal typing systems (Java, C#) where the type name matters.
interface Point {
x: number;
y: number;
}
// An object literal with the right shape is assignable
const p: Point = { x: 1, y: 2 }; // ✅
// A class with the right shape is also assignable
class Vector {
constructor(public x: number, public y: number) {}
}
const v: Point = new Vector(3, 4); // ✅ — Vector is structurally compatible
// Extra properties are fine when assigning to a less specific type
const extended = { x: 1, y: 2, label: 'origin' };
const p2: Point = extended; // ✅ — subset assignment (not a fresh literal)
// ❌ Fresh object literals trigger excess property checks
const p3: Point = { x: 1, y: 2, label: 'origin' }; // Error: 'label' not in Point
Practical implications:
implements to satisfy an interface — the shape is enoughfunction printPoint(p: Point) { console.log(p.x, p.y); }
// All of these work — all have x and y:
printPoint({ x: 1, y: 2 });
printPoint(new Vector(1, 2));
printPoint({ x: 1, y: 2, z: 3 }); // extra props OK in this context