ProgrammingTypeScript/Fullstack developer

How do Conditional Types work with infer in TypeScript, in what situations are they needed, and what errors are commonly encountered in practice?

Pass interviews with Hintsage AI assistant

Answer.

Conditional Types using the infer keyword allow you to extract types from complex data types. A classic example is extracting the element type from an array:

type ElementType<T> = T extends (infer U)[] ? U : T;

Here, infer U allows you to compute the type of the array element T. If T is an array, the type of its elements will be returned; otherwise, T itself will be returned.

Where they are used:

  • For writing generic helper types (for example, extracting the return type from a function, the type of Promise value, etc.).

Example:

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

Trick question.

Can you use multiple infer statements in a single conditional type? How does TypeScript interpret this case?

Wrong answer:

  • "You cannot use more than one infer, TypeScript won't allow it."

Correct answer:

  • You can use multiple infer variables in a single template. For example, when destructuring a tuple:
type FirstArgument<T> = T extends (infer F, ...any[]) => any ? F : never; // But it's more correct with functions: type Args<T> = T extends (...args: infer A) => any ? A : never;
  • TypeScript correctly infers multiple types through different infer variables.

Examples of real errors due to ignorance of the topic's nuances.


Story

A developer wrote a way to obtain the type of an object returned by a function but did not account for the possibility that the function might return a Promise. As a result, the return type was always Promise<any>, as no nested conditional with extract/infer was used. The code had to be refactored throughout the codebase.


Story

A generic type for unpacking nested arrays was introduced in the project, but the final else-branch was forgotten in the condition. TypeScript did not raise any error, but in some cases, the result was never, causing some utility typings in external libraries to break.


Story

A colleague attempted to extract property types from a large interface using a combine-conditional/infer type, but did not consider that some properties were themselves union types. As a result, unexpected combinations of union types were produced on output; the compiler passed them, but the logic worked incorrectly.