🔀
Discriminated Unions — The Pattern Used Instead of Enums in TypeScript
Branch on a type field and TypeScript auto-narrows types in each branch
Branch on shape.kind and TypeScript auto-narrows shape's type inside each case.
Why Instead of Enums
Enums generate runtime code (reverse mapping object). Discriminated unions exist only at type level — zero runtime cost.
Exhaustive Check
Use never type to verify all cases handled at compile time. Same effect as Rust's exhaustive match.
Key Points
1
Add a common literal field (kind, type) to each union member = discriminant
2
switch/if on discriminant → TypeScript auto-narrows types
3
never type for exhaustive check — compile error on missing cases
4
Zero runtime cost vs enum + equal or better type safety
Use Cases
Redux actions — { type: "INCREMENT" } | { type: "SET_VALUE", payload: number }
API responses — { status: "success", data: T } | { status: "error", message: string }