kind Discriminated Unions

Last updated: 2026-10-22

kind Discriminated Unions

A discriminated union (also called a tagged union) ties a group of types together with a common discriminant field (status, kind...) whose value is a distinct literal per member. When you switch on the discriminant, TypeScript narrows to the matching member — the most practical union pattern in business modeling.

GroupNarrowing & Assertions
KindType
Strict modeNot required

ℹ️ Info The editor transpiles TypeScript to JavaScript and runs it (no type checking); see each example's Output for type-check results.

📝 Syntax

type Result<T> =
  | { status: "loading" }
  | { status: "success"; data: T }
  | { status: "error"; message: string };

function handle<T>(res: Result<T>) {
  switch (res.status) {
    case "loading": /* res: no data */ break;
    case "success": res.data; break;   // narrowed to the success member
    case "error":   res.message; break;
  }
}

⚙️ Parameters

discriminantThe discriminant: every member must declare it, with a distinct literal type per member (e.g. "loading" / "success" / "error")

Returns:None — discriminated unions are a type-level modeling device; narrowing is triggered by switch/if comparisons on the discriminant and happens at compile time.

▶ Example

Edit the code below and click Try it to see the transpiled result:

Output:

loading…
got 3 items
error: timeout

(Runtime output after transpilation; res.data type-checks in the success branch thanks to discriminant narrowing — guaranteed statically by tsc, at runtime there are only values)

💡 Notes

ℹ️ Info The discriminant name is up to you — type, kind, status, state, tag are all common; what matters is a distinct literal value per member so TS can identify it uniquely.
⚠️ Note The discriminant must be a required field of literal type. Writing string instead of a literal like "success", or making it optional, destroys the discriminating power and narrowing stops working.
💡 Tip Discriminated unions pair perfectly with exhaustiveness checking: once every discriminant value is switched, adding a member makes the compiler flag every missed branch (use assertNever — see the exhaustive-checks entry).
More cases coming soon.

📚 Related tutorials

❓ FAQ

Q How is a discriminated union different from a plain union?
A A plain union narrows only via generic checks like typeof/in; a discriminated union adds a literal discriminant so a single switch lands you on exactly one member, and it enables exhaustiveness checking. Design a discriminant whenever you can.
Q Can the discriminant be nested inside an object?
A Yes — TS narrows on nested discriminants (and even array elements), e.g. res.meta.state. But deep nesting hurts readability; the convention is a top-level discriminant.
Q Can a numeric enum serve as the discriminant?
A Yes. Enum members (numeric included) are literal types, so distinct enum values per member form a valid discriminated union; string enums read better than numeric ones when debugging.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏