Discriminated Unions
Discriminated Union
If you have a class with a literal member then you can use that property to discriminate between union members.
As an example consider the union of a Square and Rectangle, here we have a member kind that exists on both union members and is of a particular literal type:
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
type Shape = Square | Rectangle;If you use a type guard style check (==, ===, !=, !==) or switch on the discriminant property (here kind) TypeScript will realize that the object must be of the type that has that specific literal and do a type narrowing for you :)
function area(s: Shape) {
if (s.kind === "square") {
// Now TypeScript *knows* that `s` must be a square ;)
// So you can use its members safely :)
return s.size * s.size;
}
else {
// Wasn't a square? So TypeScript will figure out that it must be a Rectangle ;)
// So you can use its members safely :)
return s.width * s.height;
}
}Exhaustive Checks
Quite commonly you want to make sure that all members of a union have some code(action) against them.
As an example of where stuff goes bad:
You can do that by simply adding a fall through and making sure that the inferred type in that block is compatible with the never type. For example if you add the exhaustive check you get a nice error:
That forces you to handle this new case :
Switch
TIP: of course you can also do it in a switch statement:
strictNullChecks
If using strictNullChecks and doing exhaustive checks, TypeScript might complain "not all code paths return a value". You can silence that by simply returning the _exhaustiveCheck variable (of type never). So:
Redux
A popular library that makes use of this is redux.
Here is the gist of redux with TypeScript type annotations added:
Using it with TypeScript gives you safety against typo errors, increased refactor-ability and self documenting code.
Last updated
Was this helpful?