function throwAppError(msg: string): never {
thrownew Error(msg);
}
// Used for exhaustive checkstype Shape = "circle" | "square";
function getArea(shape: Shape): number {
switch (shape) {
case"circle": return Math.PI * 10;
case"square": return100;
default:
const _exhaustive: never = shape;
return _exhaustive;
}
}
output
// never means this code path should be unreachable
Note never represents values that never occur. A function returning never must not return normally (throw or infinite loop). Assigning to never in a default branch ensures you handle every union member — adding a new Shape member causes a compile error.
function assertNever(value: never): never {
thrownew Error(`Unexpected: ${value}`);
}
example
type PaymentMethod = "card" | "bank" | "crypto" | "paypal";
function processPayment(method: PaymentMethod): string {
switch (method) {
case"card":
return"Processing card payment";
case"bank":
return"Processing bank transfer";
case"crypto":
return"Processing crypto payment";
case"paypal":
return"Processing PayPal";
default:
// If a new member is added to PaymentMethod,// this line causes a compile errorconst _exhaustive: never = method;
thrownew Error(`Unknown method: ${_exhaustive}`);
}
}
output
// Adding a fifth payment method causes a compile error at the never assignment
Note The never trick ensures you handle every union member. When a new member is added, TypeScript sees it is not handled and cannot assign it to never. This is critical for state machines, reducers, and any logic that must cover all cases. Some teams extract this into a shared assertNever utility function.