Suggest an editImprove this articleRefine the answer for “What does "discriminated union" mean?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)A **discriminated union** is a union of several object types where **each type shares a common tag field (a discriminant)** that unambiguously indicates which variant the object belongs to. **Key point:** it is a union whose members all share a common property, and by its value TypeScript understands exactly which type it is dealing with.Shown above the full answer for quick recall.Answer (EN)Image## 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 ```javascript 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 `kind` is the **discriminant** - TypeScript **automatically narrows the type** based on its value - You can safely access `radius` or `side`, without `as` and without errors --- ## Why this is convenient In a regular union type, TS does not know which specific object is being used: ```javascript 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 ```javascript 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): ```javascript 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 the `switch` no longer covers all variants. --- ## Example 4. A real-world scenario (API response) ```javascript 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**For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.