CPCODELAB
TypeScript

Discriminated Unions

10 min read

Discriminated Unions

A discriminated union (also called a tagged union) is a union of object types where each member has a literal property in common — the discriminant — that uniquely identifies it. TypeScript uses this to narrow the union exhaustively inside switch statements.

ts
type LoadingState = { status: "loading" };
type SuccessState = { status: "success"; data: string[] };
type ErrorState   = { status: "error"; message: string };

type FetchState = LoadingState | SuccessState | ErrorState;

function render(state: FetchState): string {
  switch (state.status) {
    case "loading":
      return "Loading...";
    case "success":
      return state.data.join(", "); // data is available here
    case "error":
      return `Error: ${state.message}`; // message is available here
    default:
      const _never: never = state; // exhaustiveness check
      return _never;
  }
}

Discriminated unions are the idiomatic TypeScript pattern for modelling state machines, API responses, event systems, and Redux-style actions. They give you exhaustiveness checking for free.

ts
// Redux-style actions
type Action =
  | { type: "INCREMENT"; amount: number }
  | { type: "DECREMENT"; amount: number }
  | { type: "RESET" };

function reducer(state: number, action: Action): number {
  switch (action.type) {
    case "INCREMENT": return state + action.amount;
    case "DECREMENT": return state - action.amount;
    case "RESET":     return 0;
  }
}

Always add a never-typed default case in exhaustive switches. If you add a new union member later and forget to handle it, TypeScript will report a type error in the default branch.

Ready to test yourself?
Practice TypeScript— quiz & coding exercises