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