Type Guards
Narrow types with custom guards
type Shape =
| { kind: "circle"; radius: number }
| { kind: "rect"; width: number; height: number }
| { kind: "triangle"; base: number; height: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rect":
return shape.width * shape.height;
case "triangle":
return 0.5 * shape.base * shape.height;
default: {
// Exhaustiveness check: fails compilation if a case is missing
const _exhaustive: never = shape;
return _exhaustive;
}
}
}
console.log(area({ kind: "circle", radius: 5 }).toFixed(2));
console.log(area({ kind: "rect", width: 4, height: 6 }));
console.log(area({ kind: "triangle", base: 4, height: 3 }));
// User-defined type predicate
function isNonEmptyString(x: unknown): x is string {
return typeof x === "string" && x.length > 0;
}
const values: unknown[] = ["hello", "", 42, null];
const strings = values.filter(isNonEmptyString);
console.log(strings); // inferred as string[]