0
0
Typescriptprogramming~7 mins

Exhaustive pattern matching in Typescript

Choose your learning style9 modes available
Introduction

Exhaustive pattern matching helps you check all possible cases in your code. It makes sure you don't miss any option, so your program works correctly and safely.

When you have a variable that can be one of several fixed types or values.
When you want to handle every possible case explicitly to avoid bugs.
When working with union types or discriminated unions in TypeScript.
When you want the compiler to warn you if you forget to handle a case.
When you want clearer and safer code that is easier to maintain.
Syntax
Typescript
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; size: number }
  | { kind: 'rectangle'; width: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.size ** 2;
    case 'rectangle':
      return shape.width * shape.height;
    default:
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}

The default case with never type ensures all cases are handled.

If a new shape is added, TypeScript will show an error if you forget to handle it.

Examples
This example shows exhaustive matching on a simple string union type.
Typescript
type Status = 'loading' | 'success' | 'error';

function handleStatus(status: Status) {
  switch (status) {
    case 'loading':
      console.log('Loading...');
      break;
    case 'success':
      console.log('Success!');
      break;
    case 'error':
      console.log('Error occurred');
      break;
    default:
      const _exhaustiveCheck: never = status;
      return _exhaustiveCheck;
  }
}
This example uses exhaustive matching on a discriminated union with objects.
Typescript
type Response =
  | { type: 'text'; content: string }
  | { type: 'json'; data: object };

function processResponse(response: Response) {
  switch (response.type) {
    case 'text':
      return response.content;
    case 'json':
      return JSON.stringify(response.data);
    default:
      const _exhaustiveCheck: never = response;
      return _exhaustiveCheck;
  }
}
Sample Program

This program defines a Shape type with three kinds. The area function uses exhaustive pattern matching to calculate the area. It prints the area for each shape.

Typescript
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; size: number }
  | { kind: 'rectangle'; width: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.size ** 2;
    case 'rectangle':
      return shape.width * shape.height;
    default:
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}

const myCircle: Shape = { kind: 'circle', radius: 3 };
const mySquare: Shape = { kind: 'square', size: 4 };
const myRectangle: Shape = { kind: 'rectangle', width: 5, height: 2 };

console.log('Circle area:', area(myCircle));
console.log('Square area:', area(mySquare));
console.log('Rectangle area:', area(myRectangle));
OutputSuccess
Important Notes

Exhaustive pattern matching helps catch missing cases at compile time, reducing bugs.

Time complexity depends on the number of cases, usually O(1) for switch statements.

Common mistake: forgetting the default case with never type, which disables exhaustiveness checking.

Use exhaustive matching when you want safety and clarity over your union types.

Summary

Exhaustive pattern matching checks all possible cases in a union type.

It uses a switch statement with a default case that assigns to never to ensure completeness.

This technique helps prevent bugs by making sure you handle every case explicitly.