Skip to main content

Structural typing in interfaces

1. What is structural typing

Structural typing is a principle by which type compatibility is determined by their shape (structure), not by the type's name.

Put simply:

if an object looks like an interface, TypeScript considers it to match that interface.


Example

javascript
interface User { id: number; name: string; } const person = { id: 1, name: "Tim", age: 25, }; // It can be assigned - the structure matches const u: User = person;

Although person is not declared as User, TypeScript sees that it has all the required fields (id and name), and considers the types compatible.

Extra fields (age) don't get in the way.


2. Unlike nominal typing

In some languages (for example, Java, C#, Swift) type compatibility is checked by name or by declaration, not by structure.

Example (how it would be with nominal typing):

javascript
class User { int id; String name; } class Person { int id; String name; } // Error - the types are different, even though the fields are the same User u = new Person();

In TypeScript, it's the opposite - what matters is that the structure matches. This makes the language more flexible and more "utilitarian".


3. How TypeScript checks structural compatibility

TypeScript compares the shape of objects, not their "origin".

Example:

javascript
interface Point { x: number; y: number; } const coord = { x: 10, y: 20, z: 30 }; const p: Point = coord; // OK

The check is: "Does coord have the x and y properties of the required types?" - Yes -> so it matches Point.


4. Structural typing also works with functions

javascript
interface Logger { (msg: string): void; } function logToConsole(message: string) { console.log(message); } const logger: Logger = logToConsole; // OK

TypeScript checks the function signature, not what it's called.


5. Why this matters

Thanks to structural typing:

  • you can use inline objects without explicit interfaces;
  • types become flexible and compatible;
  • it's easy to work with external data (API, JSON);
  • there's less "ceremony" (less boilerplate code).

Example: "duck typing"

"If something quacks like a duck and looks like a duck, TypeScript considers it a duck."

javascript
interface Duck { quack(): void; } const animal = { quack: () => console.log("Quack!"), }; const d: Duck = animal; // OK - the structure matches

6. How structural typing affects interfaces

Interfaces in TypeScript:

  • are not real entities at runtime;
  • only define the shape of data;
  • work on the principle of structural matching.

Example:

javascript
interface Car { wheels: number; } interface Truck { wheels: number; } let c: Car = { wheels: 4 }; let t: Truck = c; // OK - the structure matches

Although Car and Truck are different interfaces, TypeScript considers them compatible, because they have the same structure.


7. When this can be unexpected

Sometimes structural typing leads to "too flexible" behavior:

javascript
interface Point2D { x: number; y: number; } interface Point3D { x: number; y: number; z: number; } const point3D: Point3D = { x: 1, y: 2, z: 3 }; const p2d: Point2D = point3D; // OK

TypeScript has no objection - after all, point3D has everything Point2D needs. But this can lead to logical errors if you expected a 2D point.


8. Structural typing and classes

Classes are also structurally typed. That is, it doesn't matter "what" they inherit from - what matters is what's in them.

javascript
class Person { name = "Tim"; } interface Named { name: string; } let p: Named = new Person(); // OK - the fields match

Even though Person doesn't "implement" the Named interface, it's still compatible with it.


Summary

Structural typing is a way of checking types in TypeScript in which compatibility is determined by structure, not by name.

That is: if an object contains all the required properties of the required types, it is considered compatible with the interface.

Benefits:

  • flexibility and convenience when working with data;
  • less code (no need to explicitly "implements" everything);
  • ideal for JSON, APIs, functions, and objects.

Downside:

  • you can accidentally pass "extra" data and not notice a logic mismatch.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.