0
0
Typescriptprogramming~5 mins

Discriminated union narrowing in Typescript

Choose your learning style9 modes available
Introduction

Discriminated union narrowing helps TypeScript know exactly which type you are working with by checking a special property. This makes your code safer and easier to understand.

When you have a variable that can be one of several types with a common property.
When you want to run different code depending on the exact type of an object.
When you want TypeScript to help catch mistakes by knowing the exact type after a check.
When handling different shapes of data that share a common tag or kind property.
When writing functions that accept multiple related types and need to behave differently.
Syntax
Typescript
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; size: number };

function area(shape: Shape) {
  if (shape.kind === 'circle') {
    // shape is narrowed to circle
  } else if (shape.kind === 'square') {
    // shape is narrowed to square
  }
}

The kind property is the discriminant that TypeScript uses to narrow the type.

Use simple string or number literals for the discriminant property for best results.

Examples
Here, type is the discriminant property. Checking it narrows the type inside each branch.
Typescript
type Pet =
  | { type: 'dog'; barkVolume: number }
  | { type: 'cat'; livesLeft: number };

function describePet(pet: Pet) {
  if (pet.type === 'dog') {
    console.log(`Dog barks at volume ${pet.barkVolume}`);
  } else {
    console.log(`Cat has ${pet.livesLeft} lives left`);
  }
}
Using a switch on the discriminant property status narrows the type in each case.
Typescript
type Response =
  | { status: 'success'; data: string }
  | { status: 'error'; message: string };

function handleResponse(res: Response) {
  switch (res.status) {
    case 'success':
      console.log(`Data: ${res.data}`);
      break;
    case 'error':
      console.log(`Error: ${res.message}`);
      break;
  }
}
Sample Program

This program defines a Vehicle type with two shapes. The describeVehicle function uses the kind property to know which shape it is working with and prints details accordingly.

Typescript
type Vehicle =
  | { kind: 'car'; wheels: 4; brand: string }
  | { kind: 'bike'; wheels: 2; hasBell: boolean };

function describeVehicle(vehicle: Vehicle) {
  if (vehicle.kind === 'car') {
    console.log(`Car brand: ${vehicle.brand}, wheels: ${vehicle.wheels}`);
  } else if (vehicle.kind === 'bike') {
    console.log(`Bike has bell: ${vehicle.hasBell}, wheels: ${vehicle.wheels}`);
  }
}

const myCar: Vehicle = { kind: 'car', wheels: 4, brand: 'Toyota' };
const myBike: Vehicle = { kind: 'bike', wheels: 2, hasBell: true };

describeVehicle(myCar);
describeVehicle(myBike);
OutputSuccess
Important Notes

Always use a common property with unique literal values for each type to enable discriminated union narrowing.

TypeScript automatically narrows the type inside the branches after checking the discriminant.

This technique helps avoid manual type assertions and makes your code safer.

Summary

Discriminated union narrowing uses a shared property to tell TypeScript which type you have.

Check the discriminant property to safely access type-specific properties.

This makes your code easier to read and less error-prone.