Extending types in TypeScript

Kenny DuMez
Kenny DuMez
Graphite software engineer

TypeScript, a strongly typed superset of JavaScript, provides various mechanisms to extend existing types. In this guide, we'll explore different ways to extend types in TypeScript, including interfaces, type aliases, and utility types.

Type extension is the process of taking an existing type and creating a new type that adds new properties, modifies existing ones, or both. This allows you to specialize a base type for use in different contexts.

Interfaces in TypeScript are a powerful way to define contracts within your code and they can be extended using the extends keyword. This is one of the most straightforward methods to extend a type.

Terminal
interface Person {
name: string
age: number
}
interface Employee extends Person {
employeeId: number
}
const employee: Employee = {
name: 'John Doe',
age: 30,
employeeId: 123
}

In the above example, the Employee interface extends the Person interface by adding an employeeId property. An object of type Employee must now contain all the properties of Person plus the additional employeeId property.

Type aliases can also be extended by a slightly different approach from interfaces. Since type aliases can't be directly extended using extends, you can use intersection types to achieve similar functionality.

Terminal
type Animal = {
name: string
}
type Bear = Animal & {
hasHoney: boolean
}
const bear: Bear = {
name: 'Winnie',
hasHoney: true
}

Here, the Bear type is an extension of the Animal type, adding a new hasHoney property. The intersection type (&) combines multiple types into one.

TypeScript includes several built-in utility types that make it easier to transform types. For example, you can use the Partial<T> utility type to make all properties of type T optional, which can be extended further as needed.

Terminal
interface Product {
id: number
name: string
price: number
}
type UpdatedProduct = Partial<Product> & {
updatedAt: Date
}
const update: UpdatedProduct = {
id: 1,
updatedAt: new Date()
}

In this case, UpdatedProduct uses Partial<Product> to allow for partial updates to a product, where only some properties need to be provided, along with the additional updatedAt property.

  • Prefer interfaces over type aliases for extension: If you anticipate needing to extend a type, use an interface rather than a type alias, as interfaces are designed to be easily extendable.
  • Use intersection types only when absolutely needed: While intersection types are powerful, they can lead to complex types if overused. Use them sparingly, and keep type definitions clear and manageable.
  • Utilize utility types: TypeScript’s utility types are designed to facilitate common type transformations. Leveraging these can reduce boilerplate and enhance type safety.

For further reading on extending types in TypeScript, see the official TypeScript documentation.

Graphite
Git stacked on GitHub

Stacked pull requests are easier to read, easier to write, and easier to manage.
Teams that stack ship better software, faster.

Or install our CLI.
Product Screenshot 1
Product Screenshot 2