How to use discriminated unions in TypeScript

· Category: TypeScript

Short answer

A discriminated union is a union of object types that share a common literal property (the discriminant), enabling exhaustive type narrowing with switch statements.

Steps

  1. Define a shared discriminant: type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number };
  2. Narrow with a switch: switch (shape.kind) { case 'circle': return Math.PI * shape.radius ** 2; ... }
  3. Use a default case with a helper that accepts never to enforce exhaustiveness.
  4. Keep the discriminant a required literal string for reliable narrowing.
  5. Avoid optional discriminants because they break narrowing guarantees.

Tips

  • Discriminated unions are ideal for Redux actions, state machines, and API result types.
  • The exhaustiveness check ensures you handle every variant when adding new cases.

Common issues

  • Using a non-literal type for the discriminant prevents TypeScript from narrowing correctly.
  • Forgetting to handle a case causes compile errors if you implement an exhaustive check helper.