TypeScript Type Narrowing: Master Discriminated Unions for Flawless Conditional Logic

Every TypeScript codebase eventually meets the same bug: a value that can be one of several shapes, and a conditional that quietly assumes the wrong one. A loading spinner renders while data is still undefined. An error message prints undefined because the "success" branch ran on a failed response. A new event type ships and three switch statements silently ignore it.

TypeScript discriminated unions are the most reliable tool for preventing this class of mistake. Combined with type narrowing, they let the compiler prove which fields exist in each branch of your code, and they warn you the moment a new variant appears that you have not handled.

This guide takes you from the fundamentals of type narrowing to production patterns: switch narrowing, exhaustiveness checking with never, Result types, React UI state, reducers, runtime validation with Zod, and the pitfalls that make narrowing "mysteriously" stop working. Every example is plain TypeScript you can paste into a project or the TypeScript Playground.

What you will learn:

  • How type narrowing and control flow analysis work
  • How to model mutually exclusive states with a discriminated union
  • How to enforce exhaustive handling with and