TypeScript · Types that pay for themselves
What is a discriminated union?
Short answer
A discriminated union gives each member a shared literal property, usually kind or type. Checking that property narrows the whole object, which makes state machines and API results safe to handle.
A discriminated union is a union of object types that share a literal discriminant property. Because the property has a different literal value in each member, checking it tells the compiler exactly which shape is present. The rest of the object's fields are then available without casts.
type State =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: string[] }
| { status: "error"; message: string };
function render(state: State): string {
switch (state.status) {
case "success":
return state.data.join(", ");
case "error":
return state.message;
default:
return state.status;
}
}Why the discriminant matters
- The discriminant must be a literal type, not a broad string
- Each member can carry fields that only make sense in that state
- Checking the discriminant narrows the entire object
- The pattern works with switch, if and user-defined guards
- It makes impossible combinations unrepresentable
A common mistake is making variant fields optional on a single interface. That allows states like loading with data or success without data, which the type cannot prevent. Separate members with a literal discriminant model the real states more accurately.
Follow-ups you should expect
Interviewers use these to check whether the first answer was understanding or memorisation.
- 1Why must the discriminant be a literal type?
- 2How does switch narrow a discriminated union?
- 3What is the alternative to optional variant fields?
- 4Can a discriminated union have a default case?
Say it in the interview
A discriminated union puts a shared literal field on every variant. Checking that field narrows the entire object, so I can access variant-specific data safely. I use it for UI state, API results and state machines because it makes impossible states hard to represent. The key is that the discriminant is a literal type, not a broad string.
Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.
Related questions
Reading is step one
Now say it out loud.
Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live TypeScript mock interview and get scored feedback on depth, clarity and confidence.