What does "discriminated union" mean?
What a Discriminated Union is
A discriminated union is a union (union) of several object types
where each type shares a common tag field (a discriminant)
that unambiguously indicates which variant the object belongs to.
In other words: it is a union whose members all share a common property, and by its value TypeScript understands exactly which type it is dealing with.
Example 1. A simple discriminated union
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number };
function getArea(shape: Shape): number {
if (shape.kind === "circle") {
// Here shape: { kind: "circle"; radius: number }
return Math.PI * shape.radius ** 2;
} else {
// Here shape: { kind: "square"; side: number }
return shape.side ** 2;
}
}- The common field
kindis the discriminant - TypeScript automatically narrows the type based on its value
- You can safely access
radiusorside, withoutasand without errors
Why this is convenient
In a regular union type, TS does not know which specific object is being used:
type Circle = { radius: number };
type Square = { side: number };
type Shape = Circle | Square;
function area(shape: Shape) {
// shape.radius Error: Square has no radius
}If you add a common field (kind), TypeScript can figure out which is which on its own.
Example 2. Several type variants
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number }
| { kind: "triangle"; base: number; height: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.side ** 2;
case "triangle":
return (shape.base * shape.height) / 2;
}
}Inside each case, TypeScript knows exactly
which fields are available, and suggests them in autocomplete.
Example 3. Exhaustiveness check
Discriminated unions let you control that all possible variants are handled (important when extending types):
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.side ** 2;
case "triangle":
return (shape.base * shape.height) / 2;
default:
// Error, if a new type appears without a case
const _exhaustiveCheck: never = shape;
return _exhaustiveCheck;
}
}This way, if you add a new type (for example,
"rectangle"), TS immediately shows that theswitchno longer covers all variants.
Example 4. A real-world scenario (API response)
type ApiResponse =
| { status: "success"; data: string }
| { status: "error"; message: string }
| { status: "loading" };
function handleResponse(res: ApiResponse) {
switch (res.status) {
case "success":
console.log("Data:", res.data);
break;
case "error":
console.error("Error:", res.message);
break;
case "loading":
console.log("Loading...");
break;
}
}A single discriminating key (
status) fully describes the state. A very popular pattern in React code and Redux logic.
Rules for discriminated union types
| Requirement | Description |
|---|---|
| A common field (discriminant) | All variants must have the same property (for example, kind, type, status) |
| Unique values | Each discriminant value is unique to its own variant |
| The field's type is a literal | Usually a string literal ("circle", "error", "admin") |
| TS automatically narrows the type | An if or switch check performs narrowing without casts |
Discriminated union vs regular union
| Kind | Example | Can TS narrow the type automatically? |
|---|---|---|
| Regular union | { radius: number } | { side: number } | No |
| Discriminated union | { kind: "circle" } | { kind: "square" } | Yes |
Summary
| Term | Meaning |
|---|---|
| Discriminated union | A union of types with a shared "discriminating" field |
| Why it is needed | So TypeScript can precisely determine the type from the field's value |
| How it is denoted | Via ` |
| Main benefit | Safe and convenient type narrowing without manual checks |
| Typical use | Statuses, data shapes, API responses, shapes, component states |
In short:
A discriminated union is a union of objects that share a common tag field (for example,
kind), and by the value of that tag TypeScript automatically understands which type it is
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.