ProgrammingFullstack Developer

How does structural typing work in TypeScript? How does it differ from nominative typing, what are its strengths, and what pitfalls can occur?

Pass interviews with Hintsage AI assistant

Answer.

Background

Unlike many object-oriented languages, TypeScript implements structural typing (duck typing): an object is considered to match a type if it has all the necessary properties, regardless of whether it is explicitly declared as that type.

Problem

This flexibility can sometimes lead to unexpected acceptance of objects as a type if the structure matches, even though they are not meaningfully related. This is dangerous with complex data models where structure coincidentally aligns.

Solution

Always structure object types correctly, minimize structural matches of different entities, and for critical cases, use additional properties or symbols for "nominalization" of types.

Code example:

interface Point { x: number; y: number; } interface Pixel { x: number; y: number; } function drawPoint(p: Point) { console.log(p.x, p.y); } const pixel: Pixel = { x: 1, y: 2 }; drawPoint(pixel); // OK, types are structurally compatible

Key features:

  • Structural checks (properties and their types) rather than by type name
  • Ease of integration with existing JS code
  • Possible conflicts when matching structurally different objects

Tricky questions.

If the structure of two interfaces matches, does it mean they are completely interchangeable?

Probably in structure, but not in program logic. This is acceptable at the compiler level but can lead to logical errors (for example, Point and Pixel above).

Is it possible to prohibit structural compatibility for a certain type?

Not completely, but you can add a unique property (for example, with a symbol):

interface Brand { _brand: unique symbol; }

Now another object cannot mimic this type without the same unique symbol.

How does structural typing differ from nominative?

Structural is based on the presence of structure, nominative is based on the matching name of the type within a certain namespace. In TS, structural typing is always the default.

Typical mistakes and anti-patterns

  • Incorrect acceptance of unrelated objects with the same structure
  • Complete signature matching — inability to separate conceptually different types
  • False sense of type safety

Real-life example

Negative case

In several entities, fields unintentionally matched (for example, User and Admin as {id: number, name: string}), leading to confusion when working with API contracts.

Pros:

  • Less code, easier to extend new entities

Cons:

  • Hard to trace logical errors that the compiler doesn't catch

Positive case

Using unique "tags" of symbols and non-standard fields to delineate semantically different types with the same structure.

Pros:

  • Explicit separation by business logic
  • Additional safety and clarity of concepts

Cons:

  • Additional complexity of code
  • Requires more careful type planning