TypeScript
Exhaustive with never
Learn exhaustive checking with never.
Exhaustive with never
The never type represents a value that never occurs. In a switch statement, after all cases are covered, the remaining type becomes never. Using this property, we get a compiler error if a case is missing: a non-never type cannot be assigned where never is expected.
function assertNever(x: never): never {
throw new Error("Unexpected: " + x);
}
type Shape = { kind: "circle"; radius: number } | { kind: "square"; size: number };
function area(s: Shape): number {
switch (s.kind) {
case "circle": return Math.PI * s.radius ** 2;
case "square": return s.size ** 2;
default: return assertNever(s);
}
}
never and narrowing
When the switch covers all cases, in the default branch the remaining union type becomes never. The call assertNever(s) compiles only when s is never; if a case is missing, s is not never and a compile error occurs.
function assertNever(x: never): never {
throw new Error("Unexpected value");
}
function area(s: Shape): number {
switch (s.kind) {
case "circle": return Math.PI * s.radius ** 2;
case "square": return s.size ** 2;
default: return assertNever(s); // s: never
}
}
Exercise Exhaustive area with assertNever
Define an assertNever(x: never): never helper function (with throw new Error("Unexpected") inside). Define the Shape discriminated union type: "circle" (radius: number), "square" (size: number) members. Write an area(s: Shape): number function using switch (s.kind): for circle return Math.PI * s.radius ** 2, for square return s.size ** 2, for default write return assertNever(s);. Print the result via console.log(area({ kind: "square", size: 4 })).
Show example solution
function assertNever(x: never): never {
throw new Error("Unexpected");
}
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; size: number };
function area(s: Shape): number {
switch (s.kind) {
case "circle":
return Math.PI * s.radius ** 2;
case "square":
return s.size ** 2;
default:
return assertNever(s);
}
}
console.log(area({ kind: "square", size: 4 }));
Test yourself
-
How is the never type used in exhaustive check?
- It auto-writes switch cases
- It counts union members
- If a case is missing, assigning to never in the default branch errors
- It checks values at runtime
Show answer
If a case is missing, assigning to never in the default branch errors — The remaining type in the default branch becomes never when all cases are covered; the call assertNever(x: never) accepts only never, so a missing case causes a compile error.
-
assertNever signature
function assertNever(x: ____): never {
throw new Error("Unexpected");
}
Show answer
function assertNever(x: never): never {
throw new Error("Unexpected");
}
-
Exhaustive with never parts
- never türü
- represents no value
- default branch
- remaining type after all cases
- assertNever(s)
- errors if s is not never
- Exhaustive check
- compiler catches missing case
Next lesson: Switch exhaustive