Extend multiple interfaces in TypeScript

avatar

Borislav Hadzhiev

Mon Mar 21 20223 min read

Extend multiple interfaces in TypeScript #

Use the extends keyword to extend multiple interfaces in TypeScript, e.g. interface Developer extends Person, Employee {}. The extends keyword allows us to copy the members from the specified types and add new members to the final interface.

index.ts
interface Person { name: string; } interface Employee { id: number; salary: number; } interface Developer extends Person, Employee { language: string; } const dev: Developer = { id: 1, name: 'Tom', salary: 100, language: 'TypeScript', };

The extends keyword removes the need of having to repeat the members of other types at multiple places and shows the relation between the interfaces to the reader of the code.

You can extend from as many interfaces as necessary by separating the interfaces with a comma.

You are not required to add any new members to the final interface and can use the extends keyword to simply combine interfaces.

index.ts
interface Person { name: string; } interface Employee { id: number; salary: number; } // 👇️ Combine the Person and Employee interfaces interface Developer extends Person, Employee {} // 👇️ Alternatively use intersection type type Developer2 = Person & Employee; const dev: Developer = { id: 1, name: 'Tom', salary: 100, };

The example above shows how you can combine two or more interfaces without adding new properties to them.

If you need to override a property from one of the interfaces you extend, you can use the Omit utility type.

index.ts
interface Person { name: string; } interface Employee { id: number; salary: number; } // for multiple use - Omit<Employee, 'id' | 'salary'> interface Developer extends Person, Omit<Employee, 'id'> { id: string; // 👈️ override type of id } const dev: Developer = { id: 'dev-1', name: 'Tom', salary: 100, };

The Omit utility type constructs a new type by picking the properties from the provided type and removing the specified keys.

In the example, we removed the id property from the Employee type when extending from it, so we can override its type.

Had we not removed the property and tried to specify a different type in the Developer interface, we would have gotten an error.

index.ts
interface Person { name: string; } interface Employee { id: number; salary: number; } // ⛔️ Error: Interface 'Developer' incorrectly extends interface 'Employee'. // Types of property 'id' are incompatible. // Type 'string' is not assignable to type 'number'.ts(2430) interface Developer extends Person, Employee { id: string; // 👈️ override type of id }
TypeScript is telling us we can't extend from an interface and use the same property name with a different, incompatible type.

The best way to get around this is to remove the type when extending from the interface and override it in the new interface.

You can use a union of string literals to omit multiple properties from a type when extending.

index.ts
interface Person { name: string; } interface Employee { id: number; salary: number; tasks: string[]; } interface Developer extends Person, Omit<Employee, 'id' | 'salary'> { id: string; // 👈️ override type of property salary: string; // 👈️ override type of property language: string; } const dev: Developer = { id: 'dev-1', name: 'Tom', salary: '100 K', language: 'TypeScript', tasks: ['develop', 'test'], };

To pass multiple properties to the the Omit utility type, separate the properties with a pipe |.

The same approach can be used to remove some properties from a type when extending - omit the properties and don't redefine them.

Note that when extending from an interface, you can provide a more narrow type for the same property name.

index.ts
interface Person { name: string; } interface Employee { id: number | string; // 👈️ number OR string (wide) salary: number; } interface Developer extends Person, Employee { id: string; // 👈️ only string (narrow) language: string; } const dev: Developer = { id: 'dev-50', // 👈️ can only be string now name: 'Tom', salary: 100, language: 'TypeScript', };

The id property in the Employee interface has a type of number or string, but when extending from the interface, we specified a more narrow type of string.

The id property in the Developer interface can only be of type string.

Overriding the type of a property with a more specific one is allowed, however, you can't provide a type that's not compatible. If you need to do that, you have to use the Omit utility type to remove the specific property and override its type.

The main benefits of extending interfaces are:

  1. Reducing duplication, because we don't have to copy properties between interfaces.
  2. Signaling intent to the reader of our code that there is a relation between the two types.
Use the search field on my Home Page to filter through my more than 1,000 articles.