Discriminated unions — a tag field and a switch¶
Level: 201 · for TypeScript users modelling data with unions
Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The questions below are what the finished page has to answer.
One line: A union narrows on a tag only when each member's tag is a literal type: with kind: "circle" and kind: "square", switch (shape.kind) gives each case its member, even through const { kind } = shape; with kind: string, reading radius is TS2339.
Keywords: discriminated union, tagged union
What the finished page will answer¶
- Why does
switch (shape.kind)give eachcasethe right member when the tags are"circle"and"square", and what does tsc say when both are typedkind: string? - Why does narrowing still work after
const { kind } = shape, a feature added in TypeScript 4.4? - Can the tag be a number, a boolean or
undefined, and how is{ ok: true; value: T } | { ok: false; error: E }narrowed? - What does the checker allow in a
casewhen two members share the same tag value? - What does
JSON.stringifyprint for a tagged value, and why does the tag survive at run time where the type does not?
Examples it will need¶
-
discriminated_unions_literal_tag_tserror.ts— TS2339 for the union tagged withkind: string, and no errors for the literal-tagged switch or the destructured tag -
discriminated_unions_result_ts.ts— one line perResultvalue, the value or the error, chosen by theoktag
See also¶
- Exhaustiveness checking — making the switch prove that it covers every tag
- Primitive and literal types — the literal types that a tag must have
- Enums — the union of literals that replaces an enum
if,switchand? :— howswitchcompares at run time- Rust: Variants that carry data ↗ — the same idea built into Rust as enum variants
- Rust: Destructuring enums ↗ — taking a tagged value apart with a pattern, in Rust