The Weekly Dev

Developer News & Tutorials

Est. 2024  ·  Vol. I
The Weekly Dev

Exhaustive Checking in TypeScript Using the 'never' Type

TypeScript's 'never' type enables exhaustive checking, allowing you to verify all possible scenarios are handled and catch missing cases when new types are introduced later.

VA

By Vasili Zalimidis

Exhaustive Checking in TypeScript Using the 'never' Type

TypeScript enables exhaustive checking via the never type, allowing developers to verify all possible scenarios and avoid omitting cases — particularly when new types are introduced later.

Example: Vehicle Types with a Switch Statement

const rateMultiplier = 1.5;

type Car = { type: 'car'; rate: number };
type Motorbike = { type: 'motorbike'; rate: number };
type Vehicles = Car | Motorbike;

function getRate(vehicle: Vehicles) {
  switch (vehicle.type) {
    case 'car':
      return vehicle.rate * rateMultiplier;
    case 'motorbike':
      return vehicle.rate * rateMultiplier;
    default:
      // This should never happen!
      const shouldNeverHappen: never = vehicle;
      return shouldNeverHappen;
  }
}

Adding a New Type Later

When a developer adds a new vehicle type without updating the switch statement, TypeScript alerts them immediately:

type Bicycle = { type: 'bicycle'; rate: number }; // Added
type Vehicles = Car | Motorbike | Bicycle; // Updated

function getRate(vehicle: Vehicles) {
  switch (vehicle.type) {
    case 'car':
      return vehicle.rate * rateMultiplier;
    case 'motorbike':
      return vehicle.rate * rateMultiplier;
    default:
      const shouldNeverHappen: never = vehicle;
      // ^^^ Type 'Bicycle' is not assignable to type 'never'
      return shouldNeverHappen;
  }
}

TypeScript identifies that Bicycle could reach the default clause, triggering a compile error and reminding you to handle it.

Example: Size Options with Conditional Logic

type SizeOptions = 's' | 'm' | 'l' | 'xl';

function getSizePriceVariant(size: SizeOptions) {
  if (size === 's' || size === 'm') {
    return 1;
  } else if (size === 'l' || size === 'xl') {
    return 1.2;
  }

  // Unreachable — but if a new size is added without updating
  // this function, TypeScript will error here:
  const neverHappens: never = size;
  return neverHappens;
}

If a developer adds 'xxl' to SizeOptions without updating the function, they get:

Type 'string' is not assignable to type 'never'

Conclusion

Using TypeScript's never type creates protective mechanisms against incomplete exhaustive checking. Red flags surface whenever code is modified without accounting for updates elsewhere in the codebase.

← Back to Front Page