Extending Interfaces

Difficulty: Intermediate

Interface extension is TypeScript's mechanism for building complex interfaces from simpler ones. Using the `extends` keyword, a new interface inherits all properties from one or more parent interfaces and can add new properties or override existing ones. The syntax is `interface Child extends Parent { ... }`. This is the interface equivalent of the intersection type (`&`), but with a more explicit inheritance relationship.

A key advantage of `extends` over intersections is error detection. If you accidentally declare a property in the child interface that conflicts with the parent, TypeScript immediately shows an error. With intersection types, conflicting properties silently produce `never`, which can be confusing to debug. The explicit inheritance of `extends` makes the relationship clear and catches conflicts early.

TypeScript supports multiple interface inheritance: `interface AdminUser extends User, Permissions { ... }`. The child interface inherits properties from all listed parents and can add its own. If multiple parents have properties with the same name, those properties must have compatible types. This is similar to multiple inheritance in other languages but applied only to type structure, not implementation.

Interface extension is widely used in real-world TypeScript for modeling domain hierarchies, API response types, and component prop types. In React, for example, you might have a `BaseButtonProps` interface extended by `IconButtonProps` and `LinkButtonProps`. ORMs like Prisma use interface extension to build model types. The pattern keeps types DRY and makes the relationships between types explicit and self-documenting.

Code examples

Basic interface extension

interface Animal {
  name: string;
  sound: string;
}

interface Pet extends Animal {
  owner: string;
  vaccinated: boolean;
}

function describePet(pet: Pet): string {
  const status = pet.vaccinated ? "vaccinated" : "not vaccinated";
  return `${pet.name} (${pet.sound}) - owned by ${pet.owner}, ${status}`;
}

const dog: Pet = {
  name: "Rex",
  sound: "Woof",
  owner: "Alice",
  vaccinated: true
};

console.log(describePet(dog));

Pet extends Animal, inheriting `name` and `sound` while adding `owner` and `vaccinated`. Every Pet is also a valid Animal, but not every Animal is a Pet.

Multiple interface extension

interface Printable {
  toString(): string;
}

interface Serializable {
  toJSON(): string;
}

interface Loggable {
  logLevel: string;
}

// Extend multiple interfaces
interface LogEntry extends Printable, Serializable, Loggable {
  timestamp: string;
  message: string;
}

const entry: LogEntry = {
  timestamp: "2026-03-12T10:30:00Z",
  message: "Server started",
  logLevel: "info",
  toString() {
    return `[${this.logLevel}] ${this.timestamp}: ${this.message}`;
  },
  toJSON() {
    return JSON.stringify({ ts: this.timestamp, msg: this.message, level: this.logLevel });
  }
};

console.log(entry.toString());
console.log(entry.toJSON());

LogEntry extends three interfaces simultaneously. It must implement all inherited methods (toString, toJSON) and properties (logLevel), plus its own (timestamp, message).

Building a type hierarchy

interface BaseEntity {
  readonly id: number;
  createdAt: string;
}

interface User extends BaseEntity {
  name: string;
  email: string;
}

interface Employee extends User {
  department: string;
  salary: number;
}

function summarize(emp: Employee): string {
  return `#${emp.id} ${emp.name} (${emp.department}) - ${emp.email}`;
}

const emp: Employee = {
  id: 42,
  createdAt: "2026-01-01",
  name: "Alice Smith",
  email: "alice@company.com",
  department: "Engineering",
  salary: 120000
};

console.log(summarize(emp));
console.log(`Created: ${emp.createdAt}`);

A three-level hierarchy: BaseEntity -> User -> Employee. Each level adds properties. Employee has all properties from the chain: id, createdAt, name, email, department, and salary.

Key points

Concepts covered

extends keyword, Multiple inheritance, Interface composition, Override properties