Discriminated unions
The last lesson told object shapes apart by probing them - "does it have a
url?" That works, but it's detective work. The cleaner design, used all over
production TypeScript, is to make every shape introduce itself: give each
member of the union a shared property (conventionally kind or type)
holding a unique literal string.
type Shape =
| { kind: "circle"; radius: number }
| { kind: "rect"; width: number; height: number };
This is a discriminated union, and kind is the discriminant. Now a
switch on s.kind does everything at once: each case is a clean branch,
TypeScript narrows s to exactly that member inside it (s.radius is only
legal in the circle case), and the runtime behavior is a simple string
comparison. Redux actions, API responses, parser tokens - this pattern is
how TypeScript codebases model "one of several things."
Your task: implement area(s) for the Shape union: circles are
PI * radius^2, rectangles are width * height.
You'll practice:
- Declaring a union whose members share a literal kind tag
- Switching on the discriminant, with narrowing per case