What does the keyword extends mean in TypeScript ?
3 min readJun 8, 2024
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
<=> "🍌" | never | "🍓" | never | "🍒" | 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