Discriminated Unions in Practice
This lesson contains some facts about discriminated unions that may come in handy when using them in the wild.
We'll cover the following
Non-string discriminators
In the example from the previous lesson, we used a string literal property called type
as a discriminator. First, the discriminator doesn’t have to be called "type"
. Any property name will be fine.
Second, the discriminator doesn’t have to be a string. You can also use number literals, Boolean literals, or even enums!
The built-in IteratorResult
type in TypeScript (starting from version 3.6) uses the Boolean property done
as a discriminator.
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
interface IteratorYieldResult<TYield> {
done?: false;
value: TYield;
}
interface IteratorReturnResult<TReturn> {
done: true;
value: TReturn;
}
Using enums can help you avoid magic strings if that’s an issue for you. One advantage of this approach is that renaming discriminating values becomes much easier.
const enum ContactType { Phone, Email };
type Contact =
| { type: ContactType.Email, email: string }
| { type: ContactType.Phone, phone: number };
Multiple discriminating properties
Interestingly, a discriminator does not have to be a single property. A group of literal properties can also act as a discriminator! In such a case, every combination of values marks a different member of the union type.
Get hands-on with 1200+ tech skills courses.