Borislav Hadzhiev
Mon Mar 21 2022·3 min read
Photo by Nadine Rupprecht
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.
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.
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.
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.
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.
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 }
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.
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 |
.
Note that when extending from an interface, you can provide a more narrow type for the same property name.
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
.
Omit
utility type to remove the specific property and override its type.The main benefits of extending interfaces are: