intermediate
Discriminated unions
Represent finite state machines, API variants, exhaustive switches, and impossible states.
A discriminated union gives every variant a shared literal discriminant such as `kind` or `status`. Switching on that field narrows the payload. This models request states, domain events, command results, and workflows where impossible combinations should not compile.
type State =
| { status: 'loading' }
| { status: 'success'; data: string }
| { status: 'error'; error: Error };
Use exhaustive handling with `never` in the default branch. If the discriminant widens to `string`, narrowing loses power.
On interviews: explain why one union beats one object with many optional state fields.
Common pitfalls: mixing similar APIs and forgetting edge cases during live coding.
The trade-off is often clarity versus safety or expressiveness versus maintainability. Checklist:
- Choose a stable discriminant.
- Use exhaustive switches.
- Avoid wide string discriminants.