Exhaustive check through never
Short answer: make a discriminated union and add a never-based "guard" to the switch. Then, when a new variant is added, TypeScript will raise a compile error.
The basic technique (exhaustive check through never)
javascript
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number }
| { kind: "triangle"; base: number; height: number };
function area(s: Shape): number {
switch (s.kind) {
case "circle":
return Math.PI * s.radius ** 2;
case "square":
return s.side ** 2;
case "triangle":
return (s.base * s.height) / 2;
default:
// if a new variant appears, s will NOT be 'never' here → error
const _exhaustive: never = s;
throw new Error(`Unhandled case: ${_exhaustive}`);
}
}- When you add, for example,
{ kind: "rectangle" },sindefaultstops beingnever→ a compile error forces you to add thecase.
A variant with a helper function assertNever
Convenient if you do this check often:
javascript
function assertNever(x: never): never {
throw new Error(`Unhandled case: ${String(x)}`);
}
function area(s: Shape): number {
switch (s.kind) {
case "circle": return Math.PI * s.radius ** 2;
case "square": return s.side ** 2;
case "triangle": return (s.base * s.height) / 2;
default: return assertNever(s); // a type error fires here on a new variant
}
}Without default: a "post-switch" guard
If you don't want a default, you can require every branch to return a value,
and then check never after the switch:
javascript
function area(s: Shape): number {
switch (s.kind) {
case "circle": return Math.PI * s.radius ** 2;
case "square": return s.side ** 2;
case "triangle": return (s.base * s.height) / 2;
}
const _exhaustive: never = s; // fires when a new kind is added
return _exhaustive;
}Useful settings and linting
- The ESLint rule
@typescript-eslint/switch-exhaustiveness-checkhighlights unclosedswitchstatements. - The compiler flag
noFallthroughCasesInSwitchhelps avoid fallthrough betweencases (not about exhaustiveness, but useful).
Summary
To guarantee that a switch handles all variants of a union:
- Use a discriminant field (for example,
kind). - Add an exhaustive check by assigning to
never(indefaultor after theswitch). - (Optionally) Extract the check into
assertNever.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.