← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Discriminated Unions

typescript 2.0 Intermediate

Also Known As

tagged unions sum types variant types algebraic data types ADT

TL;DR

A union of types that each carry a shared literal field (the discriminant) allowing TypeScript to narrow exhaustively — the canonical way to model mutually exclusive states.

Explanation

Each member of the union has a shared property with a unique literal type (kind, type, status, tag). TypeScript uses the discriminant to narrow inside switch/if blocks with no runtime overhead beyond the field check. Pattern replaces: class hierarchies, boolean flags, optional fields that are only set in certain states. Exhaustiveness: add a default: const x: never = value branch to get a compile error when a new union member is added but not handled. Common in Redux actions, API response variants, result types (Ok | Err), FSM states.

Diagram

stateDiagram-v2
    [*] --> loading
    loading --> success : data fetched
    loading --> error : request failed
    success --> [*]
    error --> loading : retry

Watch Out

The discriminant field must be a literal type (string, number, boolean literal) — if it's a broad string the narrowing won't work.

Common Misconception

Discriminated unions are just regular union types — the discriminant field is what makes them powerful: TypeScript can narrow exhaustively and catch missing cases at compile time.

Why It Matters

Without discriminated unions, modelling mutually exclusive states requires optional fields that can be in impossible combinations — discriminated unions make impossible states unrepresentable.

Common Mistakes

  • Using a boolean discriminant — booleans only give two variants; use a string literal for extensibility.
  • Forgetting the never exhaustiveness check — new variants added later silently fall through.
  • Putting shared fields on the union level instead of each member — breaks narrowing.
  • Using type assertions instead of discriminant checks — bypasses the safety.

Avoid When

  • When variants share most fields and only differ in one optional aspect — a simple optional field is cleaner.
  • When the number of variants changes very frequently and exhaustiveness checking becomes a maintenance burden.

When To Use

  • Modelling FSM states, async request lifecycle (loading/success/error), or Redux action types.
  • Any time you have mutually exclusive variants that carry different data.

Code Examples

💡 Note
Replaces an ambiguous optional-field shape with a discriminated union where each state carries only the fields that exist in that state — impossible combinations are removed entirely.
✗ Vulnerable
// Impossible state possible: what if both error and data are set?
type ApiResponse = {
    loading: boolean;
    data?: User;
    error?: string;
};

if (response.data) {
    // error might also be set — ambiguous
✓ Fixed
// Discriminated union — impossible states are impossible
type ApiResponse =
    | { status: 'loading' }
    | { status: 'success'; data: User }
    | { status: 'error';   message: string };

function render(r: ApiResponse) {
    switch (r.status) {
        case 'loading': return <Spinner />;
        case 'success': return <UserCard user={r.data} />;
        case 'error':   return <ErrorMsg text={r.message} />;
        default:
            const _: never = r; // compile error if a variant is unhandled
    }
}

Added 11 Apr 2026
Views 335
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 3 pings S 1 ping M 0 pings T 0 pings W 0 pings T 2 pings F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W 1 ping T 2 pings F 0 pings S 2 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Amazonbot 20 Perplexity 3 Google 2 ChatGPT 2 SEMrush 2 Unknown AI 1 Ahrefs 1
crawler 30 crawler_json 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Replace structs with optional fields representing mutually exclusive states with a union of types each having a literal 'kind' or 'status' field.
📦 Applies To
typescript 2.0 web cli
🔗 Prerequisites
🔍 Detection Hints
\?: .*\|.*;
Auto-detectable: ✗ No typescript
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: File Tests: Update

✓ schema.org compliant