Discriminated Union Generator
Compose a tagged union from a model — a discriminant key plus a list of variants, each with its own typed fields — and get a complete, type-safe bundle: the union type, a type guard per variant, an exhaustive switch with a never default for compile-time exhaustiveness, factory constructors, and a match() pattern-matcher. The preview updates live as you edit and the whole model is captured in a shareable URL.
About this ToolHow it works, benefits & use casesTap to collapse
A discriminated (tagged) union is the TypeScript pattern that makes state machines, reducer actions and tagged results fully type-safe: every variant shares one literal property — the discriminant, like type, kind or status — and the compiler uses that tag to narrow the type inside a switch or if. This generator is a model-driven builder, not a parser: you declare a discriminant key and a list of variants, give each variant its own typed fields (with optional flags), and it assembles a complete bundle you can switch between. That bundle includes the union type itself (optionally as named interfaces such as Circle), a type guard per variant (isCircle(s): s is Circle), an exhaustive switch handler whose never default fails the build if you ever add a variant and forget to handle it, factory constructor functions per variant, and a match() helper that pattern-matches on the tag with a strongly typed handler map. Presets cover the common shapes — geometric shapes, async state, Redux-style actions, an API result and a form-field union — and the live preview re-renders instantly as you edit. The whole model is captured in a shareable URL and everything is generated in your browser.
How to Use
- 1Set a Union name (e.g. Shape) and a Discriminant key (e.g. kind, type, or status).
- 2Add variants with the Add variant button; give each a tag literal such as circle or LOADING.
- 3On each variant, add field rows — a property name plus its TypeScript type — and tick "opt" for optional fields.
- 4Toggle options: export declarations, named variant interfaces, and a readonly discriminant tag.
- 5Use the output selector to switch the live preview between Union, Guards, Switch, Factories, match() or All.
- 6Or start from a preset (Shapes, Async state, Redux action, API result, Form field), then copy, download, or share.
Key Benefits
- Model-driven builder: compose variants and fields visually instead of hand-typing every branch
- Emits a full bundle — union, per-variant type guards, exhaustive switch, factories and a match() helper
- The generated switch uses a never default for compile-time exhaustiveness checking
- Optional named variant interfaces (e.g. Circle) or anonymous inline object members
- Strongly typed match() handler map so each branch receives the narrowed variant type
- Five presets covering shapes, async state, Redux actions, API results and form fields
- Live preview, shareable URL, and fully in-browser generation with no upload
Common Use Cases
- Modeling async data as idle / loading / success / error with type-safe payloads
- Defining Redux or reducer action types that share a type discriminant
- Typing API results with ok and err branches that carry different fields
- Building shape or geometry unions where each kind has its own dimensions
- Generating guards and an exhaustive switch so a forgotten case becomes a compile error
- Producing factory constructors and a match() helper alongside the type in one paste
The tagged union type (+ named variant interfaces)
export interface Circle {
kind: 'circle';
radius: number;
}
export interface Square {
kind: 'square';
size: number;
}
export interface Triangle {
kind: 'triangle';
base: number;
height: number;
}
export type Shape =
| Circle
| Square
| Triangle;The generated switch assigns the value to a never in its default case. Add a variant later and forget to handle it, and TypeScript fails the build.
Presets
Union shape
e.g. interface Circle
freeze the discriminant
Variants
What a discriminated union buys you
A discriminated (tagged) union shares one literal property — the discriminant — across every variant. TypeScript uses that tag to narrow the type inside a switch or if, so each branch only sees the fields that branch actually has.
A complete bundle, not just a type
Beyond the union itself, the generator emits a type guard per variant, an exhaustive switch whose never default catches unhandled cases at compile time, factory constructors, and a match() helper that pattern-matches on the tag with a handler map.
Was this tool helpful?
Share Your Experience
Help others discover this tool!
Related tools
- TypeScript FormatterFormat and beautify TypeScript code
- JSON to TypeScriptGenerate TypeScript interfaces from JSON
- Regex TesterTest and debug regular expressions
- Generic Type BuilderBuild generic interfaces, mapped & conditional types and generic functions with constraints/defaults — plus a live usage example
- Type Narrowing HelperType a union and get idiomatic narrowing (typeof, in, instanceof, Array.isArray, discriminant switch) + a pattern reference
- Interface MergerMerge multiple interfaces (merged / intersection / extends / deep) with conflict detection and keep-first/last/union resolution
It is a union of object types that all share one literal property — the discriminant — set to a distinct value per variant. TypeScript reads that tag in a switch or if and narrows the value to the matching variant, so each branch only sees the fields that branch actually has. That removes a whole class of "property does not exist" bugs and makes state machines and tagged results safe to refactor.
The default case assigns the value to a variable typed never (const _exhaustive: never = value). After handling every known tag, the remaining type is never, which assigns fine. If you later add a variant but forget a case, the remaining type is no longer never and TypeScript fails to compile — turning a missed case into a build error instead of a runtime surprise.

