patterntypescriptnoneMajor
Exhaustiveness Checking with never in Switch Statements
Viewed 0 times
TypeScript 2.0+
exhaustive checknever typeswitch statementunion safetyassertNever
Error Messages
Problem
Adding a new variant to a discriminated union silently breaks switch statements that don't handle the new case, causing runtime bugs with no compile-time warning.
Solution
Add a default branch that assigns to 'never' and throws. TypeScript errors if any case leaks through.
function assertNever(x: never): never {
throw new Error(`Unexpected value: ${JSON.stringify(x)}`);
}
type Action = { type: 'INC' } | { type: 'DEC' } | { type: 'RESET' };
function reducer(state: number, action: Action): number {
switch (action.type) {
case 'INC': return state + 1;
case 'DEC': return state - 1;
case 'RESET': return 0;
default: return assertNever(action);
}
}Why
When all union members are handled, the default branch receives 'never', which is assignable to anything. Adding a new member without handling it makes the default reachable, causing a type error.
Gotchas
- Only works with discriminated unions — plain string unions need a different approach.
- The assertNever pattern requires the switch to be exhaustive at compile time; a runtime throw is still needed for safety.
Revisions (0)
No revisions yet.