Writing a Type-Level Switch Statement in TypeScript

by Peter Stuart on March 7, 2020

I recently came across a situation where I needed to write a very long conditional typeConditional types have the format T extends U ? X : Y. Read more about them in the TypeScript docs.

that looked something like this:

Rather than nesting extends expressions, which only supports a fixed number of conditions and results in a pyramid of doom in the definition of Foo, this could be better expressed using a Switch type:

type Switch<Value, [
  [Match1, Result1],
  [Match2, Result2],
  [Match3, Result3],
  ...
]> = ...

type Test1 = Switch<string, [
  [number, "number"],
  [boolean, "boolean"],
  [string, "string"]
]>;
// Test1 = "string"

Switch supports an arbitrary number of conditions, and we can write a recursive definition for it.

Defining Switch

To iterate through the array of conditions, I use the List.Head and List.Tail types from the excellent ts-toolbelt library:

import {List} from 'ts-toolbelt';

type Test1 = List.Head<[boolean, string, number]>;
// Test1 = boolean

type Test2 = List.Tail<[boolean, string, number]>;
// Test2 = [string, number]

Using Head and Tail, we can define Switch like this:

type Switch<T, Conditions extends Array<[any, any]>> = 
  List.Head<Conditions> extends never
    ? never
    : T extends List.Head<Conditions>[0]
      ? List.Head<Conditions>[1]
      : Switch<T, List.Tail<Conditions>>;

We can confirm that it works with a few test types:

type Test1 = Switch<string, [
  [number, "number"],
  [boolean, "boolean"],
  [string, "string"]
]>;
// Test1 = "string"

type Test2 = Switch<object, [
  [number, "number"],
  [boolean, "boolean"],
  [string, "string"]
]>;
// Test2 = never

type Test3 = Switch<string, []>;
// Test3 = never

To add a default case, match against any in the last condition:

type Test1 = Switch<string, [
  [number, "number"],
  [any, "default case"]
]>;
// Test1 = "default case"

For explanations of conditional types, implementing recursive types, and other advanced type techniques, check out these articles: