0
0
Typescriptprogramming~5 mins

Exhaustive checking with never in Typescript

Choose your learning style9 modes available
Introduction

Exhaustive checking helps you catch all possible cases in your code. Using never ensures you don't miss any case, making your program safer and less buggy.

When you have a function handling different types or values and want to be sure all are covered.
When using <code>switch</code> statements with union types and want to avoid missing cases.
When you want TypeScript to warn you if a new case is added but not handled.
When you want to avoid unexpected behavior by catching unhandled cases at compile time.
Syntax
Typescript
function assertNever(value: never): never {
  throw new Error(`Unexpected value: ${value}`);
}

switch (value) {
  case 'a':
    // handle 'a'
    break;
  case 'b':
    // handle 'b'
    break;
  default:
    assertNever(value); // ensures all cases handled
}

The assertNever function takes a never type, which means it should never be called if all cases are handled.

If a new case is added to the union type but not handled in the switch, TypeScript will show an error at assertNever.

Examples
This example checks all fruits. If a new fruit is added to Fruit but not handled, TypeScript will error at assertNever.
Typescript
type Fruit = 'apple' | 'banana';

function checkFruit(fruit: Fruit) {
  switch (fruit) {
    case 'apple':
      console.log('Apple is red');
      break;
    case 'banana':
      console.log('Banana is yellow');
      break;
    default:
      assertNever(fruit);
  }
}

function assertNever(x: never): never {
  throw new Error(`Unexpected value: ${x}`);
}
This example calculates area for shapes. The default case uses assertNever to catch any unknown shape kind.
Typescript
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 ** 2;
    default:
      return assertNever(shape);
  }
}

function assertNever(x: never): never {
  throw new Error(`Unexpected shape: ${JSON.stringify(x)}`);
}
Sample Program

This program moves in a direction. The assertNever function ensures all directions are handled. If you add a new direction but forget to handle it, TypeScript will warn you.

Typescript
type Direction = 'up' | 'down' | 'left' | 'right';

function move(direction: Direction) {
  switch (direction) {
    case 'up':
      console.log('Moving up');
      break;
    case 'down':
      console.log('Moving down');
      break;
    case 'left':
      console.log('Moving left');
      break;
    case 'right':
      console.log('Moving right');
      break;
    default:
      assertNever(direction);
  }
}

function assertNever(x: never): never {
  throw new Error(`Unknown direction: ${x}`);
}

move('up');
move('left');
OutputSuccess
Important Notes

Always use never with a function like assertNever to get compile-time checks.

This technique works best with union types and switch statements.

If you get an error at assertNever, it means you forgot to handle a case.

Summary

Exhaustive checking helps catch missing cases in your code.

Using never with a helper function forces you to handle all cases.

This makes your code safer and easier to maintain.