Extending & Declaration Merging

Compose interfaces with extends, and understand the merging power unique to interfaces.

Interfaces compose in two ways type aliases cannot fully match.

Extending β€” even multiple parents

interface HasId { id: number }
interface Timestamped { createdAt: Date }
interface Post extends HasId, Timestamped {
  title: string;
}

Declaration merging

Declare the same interface name twice and TypeScript merges the members into one. This is how libraries let you augment their types β€” the classic example is adding a property to Express's Request or extending the global Window.

interface Window { analyticsId: string }
// elsewhere, augmenting the same Window
interface Window { featureFlags: string[] }
// Window now has both members

Merging is a superpower and a footgun: two libraries can silently merge into the same name. Type aliases forbid it, which is sometimes exactly the safety you want.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • A third-party library's interface is augmented via declaration merging to add properties for a custom plugin.
  • A base Entity interface is extended by User and Product to inherit common timestamp fields.
  • A module augmentation adds new methods to an imported class's interface without modifying the original source.

More examples

Interface extends interface

User inherits createdAt and updatedAt from Timestamped via extends, requiring all fields on the implementing value.

Example Β· ts
interface Timestamped {
  createdAt: Date;
  updatedAt: Date;
}

interface User extends Timestamped {
  id: number;
  name: string;
}

const user: User = {
  id: 1,
  name: 'Alice',
  createdAt: new Date(),
  updatedAt: new Date(),
};

Declaration merging to augment

Declares Request twice; TypeScript merges the declarations so userId is available on the combined type.

Example Β· ts
// Original library interface
interface Request {
  method: string;
  url: string;
}

// Your augmentation in a .d.ts or the same file
interface Request {
  userId?: number; // merged in
}

const req: Request = { method: 'GET', url: '/', userId: 42 };

Extend multiple interfaces

Extends three separate interfaces at once to compose a rich Article shape without duplicating any field definitions.

Example Β· ts
interface Identifiable { id: number; }
interface Auditable    { createdAt: Date; updatedAt: Date; }
interface Taggable     { tags: string[]; }

interface Article extends Identifiable, Auditable, Taggable {
  title: string;
  body: string;
}

Discussion

  • Be the first to comment on this lesson.
Extending & Declaration Merging β€” TypeScript | SoundsCode