Discriminated unions in Typescript - Time & Space Complexity
We want to understand how the time it takes to check and use discriminated unions grows as the input changes.
Specifically, how does the program's work change when it looks at different union types?
Analyze the time complexity of the following code snippet.
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; size: number };
function area(shape: Shape): number {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2;
case 'square':
return shape.size * shape.size;
}
}
This code checks the kind of shape and calculates its area accordingly.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: A single switch-case check on the shape's kind.
- How many times: Exactly once per function call, no loops or recursion.
Since the function only checks one property once, the work stays the same no matter how many shapes we have.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 checks |
| 100 | 100 checks |
| 1000 | 1000 checks |
Pattern observation: The work grows linearly (O(n)) with the number of shapes processed.
Time Complexity: O(n)
This means checking the kind and calculating area takes time proportional to the number of shapes processed.
[X] Wrong: "Checking the kind property takes longer if there are more union types."
[OK] Correct: The check is a simple property read and switch, which does not get slower with more types because it happens once per call.
Understanding how discriminated unions work helps you write clear and efficient code that is easy to reason about, a skill valued in many coding tasks.
"What if the function had to check multiple properties or nested discriminated unions? How would the time complexity change?"
Practice
What is the main purpose of a discriminated union in TypeScript?
Solution
Step 1: Understand discriminated unions
Discriminated unions use a shared property (called the discriminant) to identify which type an object belongs to.Step 2: Purpose of discriminated unions
This helps TypeScript safely narrow types in code by checking that property.Final Answer:
To distinguish between different object types using a common property -> Option DQuick Check:
Discriminated union = common property to tell types apart [OK]
- Thinking discriminated unions convert types automatically
- Confusing with simple unions of primitives
- Believing they enforce one single type only
Which of the following is the correct syntax to define a discriminated union type in TypeScript?
type Shape = ?Solution
Step 1: Identify discriminant property
type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number } uses a common propertykindwith literal types ('circle' or 'square') to discriminate.Step 2: Check union structure
type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number } correctly uses a union of two object types distinguished bykind.Final Answer:
type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number } -> Option AQuick Check:
Discriminated union = union with common literal property [OK]
- Using intersection (&) instead of union (|)
- Missing literal type for discriminant property
- Using optional properties without discriminant
What will be the output of the following TypeScript code?
type Animal =
| { type: 'dog'; barkVolume: number }
| { type: 'cat'; livesLeft: number };
function describe(animal: Animal) {
switch (animal.type) {
case 'dog':
return `Dog barks at volume ${animal.barkVolume}`;
case 'cat':
return `Cat has ${animal.livesLeft} lives left`;
}
}
console.log(describe({ type: 'cat', livesLeft: 7 }));Solution
Step 1: Analyze the input object
The input is{ type: 'cat', livesLeft: 7 }, so thetypeis 'cat'.Step 2: Follow the switch case
The switch matches 'cat' case and returns`Cat has ${animal.livesLeft} lives left`, which becomes 'Cat has 7 lives left'.Final Answer:
Cat has 7 lives left -> Option AQuick Check:
Switch on discriminant returns correct string [OK]
- Confusing 'dog' and 'cat' cases
- Expecting runtime error due to union
- Ignoring the discriminant property
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;
}
}Solution
Step 1: Check property access in else branch
In the else branch, the code accessesvehicle.wheels, butbiketype has nowheelsproperty.Step 2: Understand TypeScript error
This causes a type error becausewheelsis not defined for{ kind: 'bike'; pedals: number }.Final Answer:
Property 'wheels' does not exist on type 'bike' object -> Option BQuick Check:
Accessing wrong property on union member causes error [OK]
- Assuming all union members share same properties
- Ignoring TypeScript error messages
- Thinking switch is mandatory over if
Given the following discriminated union, how can you safely add a new shape type rectangle with width and height properties and update the area function accordingly?
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;
}
}Solution
Step 1: Extend the union type
Add the new shape type with discriminantkind: 'rectangle'and propertieswidthandheightto theShapeunion.Step 2: Update the area function
Add a new case in the switch for 'rectangle' that returnsshape.width * shape.heightto correctly calculate the area.Final Answer:
Add { kind: 'rectangle'; width: number; height: number } to Shape union and add case 'rectangle' in switch returning width * height -> Option CQuick Check:
Extend union and handle new case in switch [OK]
- Forgetting to update the function for new type
- Removing existing cases accidentally
- Not using discriminant property in new type
Ready to prove it?
Pass the test and this pattern moves unknown
