Careeroza
Exhaustiveness Checking with never
Make the Compiler Remind You
After all cases of a union are handled, the remaining type is never. Assigning the value to a never variable in the default branch turns "I forgot a case" into a compile error.
Example
function assertNever(x: never): never {
throw new Error("Unhandled case: " + JSON.stringify(x));
}
type Shipping = { mode: "standard" } | { mode: "express" } | { mode: "pickup"; store: string };
function shippingFee(s: Shipping, cartTotal: number): number {
switch (s.mode) {
case "standard": return cartTotal >= 499 ? 0 : 40;
case "express": return 99;
case "pickup": return 0;
default: return assertNever(s);
}
}
console.log(shippingFee({ mode: "standard" }, 300));
console.log(shippingFee({ mode: "express" }, 300));
console.log(shippingFee({ mode: "pickup", store: "Koramangala" }, 300));Output
40 99 0
Adding a New Case Later
Example
Someone adds "drone" delivery but forgets the switch. The compiler points straight at it (TS2345: { mode: "drone" } is not assignable to never).
function assertNever(x: never): never {
throw new Error("Unhandled case: " + JSON.stringify(x));
}
type Shipping = { mode: "standard" } | { mode: "express" } | { mode: "drone" };
function shippingFee(s: Shipping): number {
switch (s.mode) {
case "standard": return 40;
case "express": return 99;
default: return assertNever(s);
}
}Compiler output (tsc)
Line 11: error TS2345: Argument of type '{ mode: "drone"; }' is not assignable to parameter of type 'never'.