Concept Flow - Discriminated union narrowing
Start with union type variable
Check discriminant property
Match case A
Use properties
End
We check a special property (discriminant) to know which type we have, then safely use its specific properties.
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; size: number };
function area(shape: Shape) {
if (shape.kind === "circle") {
return Math.PI * shape.radius ** 2;
} else {
return shape.size ** 2;
}
}| Step | Condition | Condition Result | Narrowed Type | Action | Output |
|---|---|---|---|---|---|
| 1 | shape.kind === "circle" | true | { kind: "circle"; radius: number } | Calculate circle area | 28.274333882308138 |
| 2 | shape.kind === "circle" | false | { kind: "square"; size: number } | Calculate square area | 16 |
| 3 | No more cases | - | - | Return result | - |
| Variable | Start | After Step 1 | After Step 2 | Final |
|---|---|---|---|---|
| shape | { kind: "circle", radius: 3 } | { kind: "circle", radius: 3 } | - | - |
| shape | { kind: "square", size: 4 } | - | { kind: "square", size: 4 } | - |
| output | - | 28.274333882308138 | 16 | - |
Discriminated union narrowing: - Use a common 'discriminant' property (like 'kind') - Check this property in conditions - TypeScript narrows type inside each branch - Access only properties valid for that narrowed type - Ensures safe, clear code for union types
What is the main purpose of a discriminated union in TypeScript?
Which of the following is the correct syntax to define a discriminated union type in TypeScript?
type Shape = ?
What will be the output of the following TypeScript code?
type Animal =
| { type: 'dog'; barkVolume: number }
| { type: 'cat'; livesLeft: number };
function describe(animal: Animal) {
if (animal.type === 'dog') {
return `Dog barks at volume ${animal.barkVolume}`;
} else {
return `Cat has ${animal.livesLeft} lives left`;
}
}
console.log(describe({ type: 'cat', livesLeft: 7 }));Identify the error in this TypeScript code using discriminated unions:
type Vehicle =
| { kind: 'car'; wheels: number }
| { kind: 'bike'; pedals: number };
function getWheels(vehicle: Vehicle) {
if (vehicle.kind === 'car') {
return vehicle.wheels;
} else {
return vehicle.wheels;
}
}Given the following discriminated union, how can you safely add a new shape type { kind: 'triangle'; base: number; height: number } and update the area function to handle it?
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; side: number };
function area(shape: Shape): number {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2;
case 'square':
return shape.side ** 2;
}
}Pass the test and this pattern moves unknown