DAY 16 OF 30
Discriminated unions
Yesterday, in one sentence
A check that narrows a type. typeof, in and an if comparing against
undefined are built in, and you can write your own function with a type
predicate return type like value is string.
Did you say:
- ✓a check that narrows a type
- ✓`typeof`, `in` and `undefined` checks are built in
- ✓you can write your own with a type predicate return type
Interview question
A return type written as value is Type. It declares that the argument is of a
particular type if the function returns true. Without it the function only
reports a boolean, so nothing is narrowed where you call it.
Did you say:
- ✓a return type written `value is Type`
- ✓declares the argument is of that type if the function returns true
- ✓without it nothing narrows at the call site
A discriminated union is a union typeUnion Type of object typesObject Type, where each one has a property with the same name and gives it a different literal typeLiteral Type. That shared property is called the discriminant.
type XMen = { kind: "mutant" }; // kind is the literal type "mutant"
type Shield = { kind: "human" }; // kind is the literal type "human"
type Asgardian = { kind: "asgardian" }; // kind is the literal type "asgardian"
type Character = XMen | Shield | Asgardian;
Checking the discriminant narrows the whole object, without needing in or a type
predicate. The discriminant has to be a literal type. If kind were string, every
object type would allow any string and TypeScript would have nothing to tell them
apart with.
function describe(character: Character) {
if (character.kind === "mutant") {
character; // character is XMen here
}
if (character.kind === "human") {
character; // character is Shield here
}
}
You can read character.kind before narrowing because every object type in the union
has it. A property that only exists on one of them would still need the in operator.
Check yourself
type Hero = { kind: string }
type Villain = { kind: string }
function act(character: Hero | Villain) {
if (character.kind === "hero") {
// ...do something
}
}
The discriminant has to be a literal type. With kind: string, both members allow any string, so checking it tells TypeScript nothing about which one you have. It needs to be kind: "hero" and kind: "villain".
A union where every member has a property with the same name, each given a different literal type. Checking that property narrows the whole object to one member.
Did you say:
- ✓a union of object types
- ✓each has the same property with a different literal type
- ✓checking that property narrows to one of them