CodePark/ questions / Conditional types & infer
START PRACTICINGPRACTICE
Frontend question · TypeScript › Conditional types & infer

Explain conditional types and the infer keyword. Implement your own ReturnType and a type that unwraps a Promise.

type MyReturnType<F> = F extends (...args: any[]) => infer R ? R : never;

type UnwrapPromise<T> = T extends Promise<infer V> ? V : T;

type A = MyReturnType<() => number>;      // number
type B = UnwrapPromise<Promise<string>>;  // string
type C = UnwrapPromise<boolean>;          // boolean

A conditional type is an if/else for types, with the form T extends U ? X : Y. infer captures part of a type by pattern matching, inside that extends check.

A conditional type works like a ternary at the type level. If T can be assigned to U, the result is X. Otherwise it is Y. It is mostly useful inside generics, where T is not known yet.

infer can only appear in the extends clause. It declares a new type variable, and TypeScript fills it in by matching the pattern. Think of it as "match this shape and give a name to the part I want".

  • In MyReturnType, the pattern is any function. infer R captures whatever its return type is.
  • In UnwrapPromise, infer V captures the value inside a Promise. A type that is not a promise does not match, so the result is T itself.

The built-in Awaited goes further. It unwraps nested promises again and again, so Promise<Promise<string>> becomes string.

  • T extends U ? X : Y is an if/else (ternary) for types.
  • infer declares a type variable that TypeScript fills in by pattern matching.
  • infer is only allowed in the extends clause of a conditional type.
  • Built-in types like ReturnType and Parameters are written this way.