Bird
Raised Fist0
Typescriptprogramming~10 mins

Discriminated unions in Typescript - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Discriminated unions
Define union types with a common 'kind' property
↓
Create a variable of the union type
↓
Use switch or if on 'kind'
↓
Handle case A
↓
Use specific properties safely
Discriminated unions use a shared 'kind' property to safely distinguish and handle different types in a union.
Execution Sample
Typescript
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; size: number };

function area(shape: Shape) {
  switch (shape.kind) {
    case 'circle': return Math.PI * shape.radius ** 2;
    case 'square': return shape.size ** 2;
  }
}
Calculates area based on the shape's kind, safely accessing properties.
Execution Table
StepActionshape.kindConditionBranch TakenResult
1Call area with {kind: 'circle', radius: 3}circleswitch on 'circle'case 'circle'Calculate area = π * 3^2 = 28.2743
2Return area for circlecircle--28.2743
3Call area with {kind: 'square', size: 4}squareswitch on 'square'case 'square'Calculate area = 4^2 = 16
4Return area for squaresquare--16
5Call area with unknown kindtriangleswitch on 'triangle'no matching caseNo result (exhaustive check error if enabled)
6Exit---Function ends
💡 Function ends after handling all known 'kind' cases or error if unknown.
Variable Tracker
VariableStartAfter Call 1After Call 2After Call 3Final
shape.kind-circlecirclesquare-
Result-28.274328.274316-
Key Moments - 3 Insights
Why do we check 'shape.kind' instead of other properties?
Because 'kind' is the shared discriminant property that tells us exactly which shape type we have, so we know which properties exist safely (see execution_table rows 1 and 3).
What happens if 'shape.kind' has a value not handled in the switch?
The function does not return a value for unknown kinds, which can cause errors or require an exhaustive check (see execution_table row 5).
Why is it safe to access 'shape.radius' only in the 'circle' case?
Because the switch on 'kind' guarantees the shape is a circle there, so 'radius' exists (see execution_table row 1).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 3, what is the value of 'shape.kind'?
Atriangle
Bcircle
Csquare
Dundefined
💡 Hint
Check the 'shape.kind' column at step 3 in execution_table.
At which step does the function handle a shape with kind 'circle'?
AStep 1
BStep 3
CStep 5
DStep 6
💡 Hint
Look for 'case 'circle'' in the 'Branch Taken' column in execution_table.
If we add a new shape kind 'rectangle', what will happen in the current switch?
AIt will be handled automatically.
BIt will cause a compile-time error if exhaustive checks are enabled.
CIt will return area as zero.
DIt will call the 'circle' case.
💡 Hint
See execution_table row 5 about unknown kinds and exhaustive checks.
Concept Snapshot
Discriminated unions use a common 'kind' property to distinguish types.
Use switch or if on 'kind' to safely access type-specific properties.
This ensures type safety and clear code.
Always handle all 'kind' cases to avoid errors.
Example:
  type Shape = {kind:'circle', radius:number} | {kind:'square', size:number};
Full Transcript
Discriminated unions in TypeScript let us combine different types that share a common property called 'kind'. This property tells us which type we have. When we write a function that takes this union type, we check the 'kind' property using a switch or if statement. This way, we know exactly which properties exist and can use them safely. For example, if 'kind' is 'circle', we can use 'radius'. If 'kind' is 'square', we use 'size'. If we get a 'kind' value that we don't expect, the function might not work correctly unless we handle that case. This pattern helps us write clear and safe code when working with different but related types.

Practice

(1/5)
1.

What is the main purpose of a discriminated union in TypeScript?

easy
A. To automatically convert types at runtime
B. To create a union of unrelated primitive types
C. To enforce a single type for all variables
D. To distinguish between different object types using a common property

Solution

  1. Step 1: Understand discriminated unions

    Discriminated unions use a shared property (called the discriminant) to identify which type an object belongs to.
  2. Step 2: Purpose of discriminated unions

    This helps TypeScript safely narrow types in code by checking that property.
  3. Final Answer:

    To distinguish between different object types using a common property -> Option D
  4. Quick Check:

    Discriminated union = common property to tell types apart [OK]
Hint: Look for a shared property that identifies each type [OK]
Common Mistakes:
  • Thinking discriminated unions convert types automatically
  • Confusing with simple unions of primitives
  • Believing they enforce one single type only
2.

Which of the following is the correct syntax to define a discriminated union type in TypeScript?

type Shape = ?
easy
A. type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number }
B. type Shape = { radius: number } & { side: number }
C. type Shape = { kind: string; radius?: number; side?: number }
D. type Shape = { circle: number } | { square: number }

Solution

  1. Step 1: Identify discriminant property

    type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number } uses a common property kind with literal types ('circle' or 'square') to discriminate.
  2. Step 2: Check union structure

    type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number } correctly uses a union of two object types distinguished by kind.
  3. Final Answer:

    type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number } -> Option A
  4. Quick Check:

    Discriminated union = union with common literal property [OK]
Hint: Look for union with a shared literal property for discrimination [OK]
Common Mistakes:
  • Using intersection (&) instead of union (|)
  • Missing literal type for discriminant property
  • Using optional properties without discriminant
3.

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 }));
medium
A. Cat has 7 lives left
B. Dog barks at volume undefined
C. TypeError at runtime
D. Cat has undefined lives left

Solution

  1. Step 1: Analyze the input object

    The input is { type: 'cat', livesLeft: 7 }, so the type is 'cat'.
  2. 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'.
  3. Final Answer:

    Cat has 7 lives left -> Option A
  4. Quick Check:

    Switch on discriminant returns correct string [OK]
Hint: Match the discriminant property in switch to get output [OK]
Common Mistakes:
  • Confusing 'dog' and 'cat' cases
  • Expecting runtime error due to union
  • Ignoring the discriminant property
4.

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;
  }
}
medium
A. Function should use switch instead of if
B. Property 'wheels' does not exist on type 'bike' object
C. Incorrect discriminant property name
D. Missing return type annotation on function

Solution

  1. Step 1: Check property access in else branch

    In the else branch, the code accesses vehicle.wheels, but bike type has no wheels property.
  2. Step 2: Understand TypeScript error

    This causes a type error because wheels is not defined for { kind: 'bike'; pedals: number }.
  3. Final Answer:

    Property 'wheels' does not exist on type 'bike' object -> Option B
  4. Quick Check:

    Accessing wrong property on union member causes error [OK]
Hint: Check property exists on all union members before access [OK]
Common Mistakes:
  • Assuming all union members share same properties
  • Ignoring TypeScript error messages
  • Thinking switch is mandatory over if
5.

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;
  }
}
hard
A. Add { kind: 'rectangle'; width: number; height: number } to Shape union and replace switch with if-else
B. Add { kind: 'rectangle'; width: number; height: number } to Shape union but no change needed in area function
C. Add { kind: 'rectangle'; width: number; height: number } to Shape union and add case 'rectangle' in switch returning width * height
D. Add { kind: 'rectangle'; width: number; height: number } to Shape union and remove existing cases

Solution

  1. Step 1: Extend the union type

    Add the new shape type with discriminant kind: 'rectangle' and properties width and height to the Shape union.
  2. Step 2: Update the area function

    Add a new case in the switch for 'rectangle' that returns shape.width * shape.height to correctly calculate the area.
  3. Final Answer:

    Add { kind: 'rectangle'; width: number; height: number } to Shape union and add case 'rectangle' in switch returning width * height -> Option C
  4. Quick Check:

    Extend union and handle new case in switch [OK]
Hint: Add new type to union and handle it in switch [OK]
Common Mistakes:
  • Forgetting to update the function for new type
  • Removing existing cases accidentally
  • Not using discriminant property in new type
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard