Skip to content

Type Checking

TypeScript uses structural type checking, which is different from nominal typing systems like Java or C#.

Structural Type Checking

Two types are considered compatible if they have the same structure, regardless of their names. This means TypeScript checks the shape and structure of objects rather than their names or inheritance hierarchy, even if the object wasn't explicitly created from a specific type definition.

ts
type Point = { x: number; y: number };

function printPoint(point: Point) {
  console.log(`Point at (${point.x}, ${point.y})`);
}

// These objects are compatible with Point even though they weren't 
// created from the Point type:
const obj1 = { x: 10, y: 20 };
const obj2 = { x: 5, y: 15, label: "origin" }; // Extra property is fine!

printPoint(obj1); // OK
printPoint(obj2); // OK - extra properties are ignored
printPoint({ x: 0, y: 99}); // OK - object literal works too

// TypeScript catches structural mismatches:
// const obj3 = { x: 10 }; // Error: missing 'y' property
// const obj4 = { x: "10", y: 20 }; // Error: 'x' must be number, not string

🤔 Duck typing and structural typing are similar, but not the same. Structural typing is a static type system that checks whether types are compatible based on their structure at compile time. In contrast, duck typing is dynamic and checks compatibility at runtime, based on whether the accessed properties and methods exist on the value.

Why This Matters

Structural typing provides several benefits:

  • Flexibility: You can use objects from different sources as long as they have the right structure
  • Interoperability: Works well with external libraries and APIs
  • Less coupling: Your code doesn't depend on specific class names or inheritance hierarchies