TypeScript
/Advanced
Discriminated Unions
Definition
A pattern where you combine Union Types with a common, literal 'discriminant' property. This allows TypeScript to definitively narrow down which object type it is dealing with.
Explain Like I'm New
Imagine a box that either contains a Dog or a Bird. Both are 'Animals'. To figure out what's inside safely, you label the box with a `type: 'dog'` or `type: 'bird'` tag. TypeScript reads this tag (the discriminant), and instantly knows, 'Ah, it's a Bird, so it must have a wingspan property.'
Real World Example
Handling Redux actions! Every action has a `type` string (e.g., 'ADD_TODO'). TS looks at the `type`, and correctly infers what data should be in the `payload`.
Common Use Cases
- •Redux Actions
- •Handling diverse API response schemas
- •State machines
Interactive Example
interface Circle { kind: "circle"; radius: number; } interface Square { kind: "square"; sideLength: number; } interface Rectangle { kind: "rectangle"; width: number; height: number; } // The Union type Shape = Circle | Square | Rectangle; function getArea(shape: Shape) { // TypeScript doesn't know what shape it is yet. // console.log(shape.radius); // Error! switch (shape.kind) { case "circle": // TS knows 100% it's a circle here return Math.PI * shape.radius ** 2; case "square": // TS knows 100% it's a square here return shape.sideLength ** 2; case "rectangle": return shape.width * shape.height; default: // EXHAUSTIVENESS CHECKING: // If someone adds a 'Triangle' to the Shape union but forgets to // add a case here, TS throws an error because Triangle cannot be assigned to never. const _exhaustiveCheck: never = shape; return _exhaustiveCheck; } }
Interview Questions
basic
- What is the 'discriminant' property?
intermediate
- How do you narrow a discriminated union?
advanced
- How do you ensure Exhaustiveness Checking using the `never` type?