typestar

Conditional types and infer in TypeScript

A type-level if, and the keyword that pulls a type out of a position.

type Unwrap<T> = T extends Promise<infer Inner> ? Inner : T;
type ElementOf<T> = T extends readonly (infer Item)[] ? Item : never;
type FirstArg<F> = F extends (first: infer A, ...rest: never[]) => unknown
  ? A
  : never;

type A = Unwrap<Promise<string>>;
type B = ElementOf<number[]>;
type C = FirstArg<(name: string, age: number) => void>;

type Flatten<T> = T extends readonly (infer Item)[] ? Flatten<Item> : T;
type Deep = Flatten<number[][][]>;

const a: A = "unwrapped";
const b: B = 42;
const c: C = "first";
const deep: Deep = 1;
console.log(a, b, c, deep);

How it works

  1. A extends B ? X : Y chooses at the type level.
  2. infer names a type in the position it appears.
  3. That is how ReturnType and Awaited are written.

Keywords and builtins used here

The run, in numbers

Lines
18
Characters to type
564
Tokens
181
Three-star pace
105 tpm

At the three-star pace of 105 tokens a minute, this run takes about 103 seconds.

Type this snippet

Step 2 of 3 in Conditional types, step 2 of 12 in Type-level programming.

← Previous Next →