What does the keyword extends mean in TypeScript ?

Thomas Rubattel
3 min readJun 8, 2024

--

A virus can mutate over the time — Photo by Fusion Medical Animation on Unsplash

extends is likely the most important keyword in TypeScript.

extends means different things depending on the context.

This makes TypeScript a bit confusing and contributes to the steepness of its learning curve for newcomers.

In this article, we’ ll see the different use cases of the extends keyword.

Type assignability check

A extends B in TypeScript is a set related operation.

One can transpose it in terms of set theory, the following: A subset of B .

type Food  = "🍌" | "🥒" | "🍓" | "🥕" | "🍒" | "🍆";

// 💡 `never`, the empty set - ∅ -, is useful for filtering
type FilterOut<T, U> = T extends U ? never : T;

type Fruits = FilterOut<Food, "🥒" | "🥕" | "🍆">; // "🍌" | "🍓" | "🍒"

// 💡 let's it break down - conditional type is distributive -
/*
FilterOut<"🍌", "🥒" | "🥕" | "🍆"> <=> {"🍌"} ⊄ {"🥒","🥕","🍆"} = {"🍌"}
|
FilterOut<"🥒", "🥒" | "🥕" | "🍆"> <=> {"🥒"} ⊂ {"🥒","🥕","🍆"} = never
|
FilterOut<"🍓", "🥒" | "🥕" | "🍆"> <=> {"🍓"} ⊄ {"🥒","🥕","🍆"} = {"🍓"}
|
FilterOut<"🥕", "🥒" | "🥕" | "🍆"> <=> {"🥕"} ⊂ {"🥒","🥕","🍆"} = never
|
FilterOut<"🍒", "🥒" | "🥕" | "🍆"> <=> {"🍒"} ⊄ {"🥒","🥕","🍆"} = {"🍒"}
|
FilterOut<"🍆", "🥒" | "🥕" | "🍆"> <=> {"🍆"} ⊂ {"🥒","🥕","🍆"} = never
*/

Type constraint

A type constraint prevent a utility type to be misused.

type ValueOf<T> = T[keyof T]; // this a so-called utility type

const Article = {
description: 'foldable mobile phone',
price: 440.65,
currency: 'USD',
manufacturer: 'Datco',
} as const;

type ArticleValues = ValueOf<typeof Article>;
// "foldable mobile phone" | 440.65 | "USD" | "Datco"

const price = 525.10;

type T = ValueOf<typeof price>; // ✅ misuse, but no compilation error

////////////////////////////////////////////////////////////////////

// 💡 Better: with type constraint

type RefinedValueOf<T extends object> = T[keyof T];

// 💥 Type 'number' does not satisfy the constraint 'object'.(2344)
type U = RefinedValueOf<typeof price>;

Type enrichment

interface Person {
first: string;
last: string;
}

interface Employee extends Person {
salary: number;
startTime: Date;
}

const thomas: Employee = {
first: "Thomas",
last: "Rubattel",
salary: 90000,
startTime: new Date("2010-12-01"),
}; // ✅

Other example:

class Animal {
constructor(protected name: string) {}

speak() {
console.log(`${this.name} makes a sound.`);
}
}

class Dog extends Animal {
constructor(name: string, private age: number) {
super(name);
}

speak() {
console.log(`${this.name} barks.`);
}
}

const dog = new Dog("Laika", 3); // ✅
dog.speak(); // "Laika barks."

Takeaway

The extends TypeScript keyword means three different things:

  • assignability check: used in conditional type
  • constraint: used especially — but not only — in utility types
  • enrichment: used in aggregation of objects type or inheritance from a class

An another article of mine closely relates to the present article. It gives some insight on how to reason about types in Typescript.

I wrote a more comprehensive article on TypeScript in general, you may have a look at it for a larger overview on TypeScript’s capabilities.

--

--