TypeScript
Switch exhaustive
Learn exhaustive checking in switches.
Switch exhaustive
In a switch statement, after all cases are written, ending the default branch with assertNever means that when a new member is added, the compiler finds all switches and reports the missing case. This guarantees the switch is exhaustive.
function assertNever(x: never): never {
throw new Error("Unexpected: " + x);
}
type Color = "red" | "green" | "blue";
function colorName(c: Color): string {
switch (c) {
case "red": return "Red";
case "green": return "Green";
case "blue": return "Blue";
default: return assertNever(c);
}
}
When a new member is added
While the existing switch is exhaustive, when a new member is added to the union, in switches that don't write all cases the c in the default branch is no longer never. The assertNever(c) call gives a compile error and reports the missing case.
type Color = "red" | "green" | "blue" | "yellow"; // yellow added
function colorName(c: Color): string {
switch (c) {
case "red": return "Red";
case "green": return "Green";
case "blue": return "Blue";
// yellow case missing!
default: return assertNever(c); // error: c may now be "yellow"
}
}
Exercise Exhaustive with a Color switch
Define an assertNever(x: never): never function (with throw new Error("Unexpected") inside). Define the Color = "red" | "green" | "blue" union type. Write a colorName(c: Color): string function using switch (c): for red return "Kırmızı", for green return "Yeşil", for blue return "Mavi", for default write return assertNever(c);. Print the result via console.log(colorName("blue")).
Show example solution
function assertNever(x: never): never {
throw new Error("Unexpected");
}
type Color = "red" | "green" | "blue";
function colorName(c: Color): string {
switch (c) {
case "red":
return "Kırmızı";
case "green":
return "Yeşil";
case "blue":
return "Mavi";
default:
return assertNever(c);
}
}
console.log(colorName("blue"));
Test yourself
-
What is done in the default branch to make the switch exhaustive?
- break is used
- return undefined is written
- console.error is written
- assertNever is called
Show answer
assertNever is called — If assertNever(c) is called in the default branch, when c is not never (a case is missing) a compile error occurs; this makes the switch exhaustive.
-
assertNever in default branch
function assertNever(x: never): never {
throw new Error("Unexpected");
}
type Color = "red" | "green" | "blue";
function colorName(c: Color): string {
switch (c) {
case "red": return "Kırmızı";
case "green": return "Yeşil";
case "blue": return "Mavi";
default:
return ____;
}
}
Show answer
function assertNever(x: never): never {
throw new Error("Unexpected");
}
type Color = "red" | "green" | "blue";
function colorName(c: Color): string {
switch (c) {
case "red": return "Kırmızı";
case "green": return "Yeşil";
case "blue": return "Mavi";
default:
return assertNever(c);
}
}
-
Switch exhaustive parts
- default branch
- remaining after all cases
- assertNever(c)
- errors if c is not never
- Yeni üye ekleme
- compiler catches missing case
- switch ifadesi
- must be exhaustive
Next lesson: Compile-time safety