> Для чего используется infer в TypeScript (TypeScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Арго

Стек: TypeScript

> Пример ответа

Короткий ответ

infer - ключевое слово в условных типах TypeScript, которое позволяет выводить (извлекать) тип из другого типа в процессе сопоставления с образцом. Оно работает только внутри ветки extends условного типа и даёт доступ к внутренним типам, например, к типу элемента массива (T extends Array<infer U> ? U : never) или типу возвращаемого значения функции (T extends (...args: any[]) => infer R ? R : never). Это мощный инструмент для создания гибких утилитарных типов.

Подробное объяснение

infer - это механизм pattern matching на уровне типов. Он объявляет переменную типа в позиции, где TypeScript может автоматически вывести конкретный тип на основе переданного аргумента. Ключевое ограничение: infer может использоваться только в части extends условного типа, после ключевого слова infer идёт имя переменной типа, которая затем доступна в ветвях true/false.

Пример базового синтаксиса:

TYPESCRIPT
type ExtractArrayItem<T> = T extends Array<infer U> ? U : never;

Здесь infer U говорит TypeScript: "если T - массив, выведи тип его элементов и назови его U, затем используй U в результате". Если T не массив - возвращается never.

infer может быть вложенным, использоваться с rest параметрами, кортежами, функциями, промисами и другими сложными типами. Например, извлечение типа возвращаемого значения функции:

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

Важно: infer не может быть использован вне условного типа, и переменная типа, объявленная через infer, видна только в пределах данного условного типа.

На практике

infer активно используется в:

  • утилитарных типах стандартной библиотеки TypeScript (ReturnType, Parameters, ConstructorParameters, InstanceType);
  • создании собственных type helpers для работы с API, Redux, React props;
  • извлечении типов из сложных структур (например, тип payload из Promise, тип элемента из Tuple, тип ключа из Record);
  • реализации type-safe middleware, HOC, декораторов;
  • построении discriminated unions и type guards на уровне типов.

Пример из реального проекта: извлечение типа данных из ответа API, обёрнутого в Promise:

TYPESCRIPT
type ApiResponse<T> = T extends Promise<infer U> ? U : T;

Пример кода

TYPESCRIPT
// Извлечение типа элемента массива
type ArrayItem<T> = T extends Array<infer U> ? U : never;
type Test1 = ArrayItem<string[]>; // string
type Test2 = ArrayItem<number[]>; // number
type Test3 = ArrayItem<boolean>; // never
// Извлечение типа возвращаемого значения функции
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Test4 = MyReturnType<() => string>; // string
type Test5 = MyReturnType<(a: number) => boolean>; // boolean
// Извлечение типа из Promise
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type Test6 = UnwrapPromise<Promise<string>>; // string
type Test7 = UnwrapPromise<number>; // number
// Извлечение первого элемента кортежа
type First<T extends any[]> = T extends [infer F, ...any[]] ? F : never;
type Test8 = First<[1, 2, 3]>; // 1
type Test9 = First<[]>; // never
// Вложенный infer: извлечение типа из вложенного Promise
type DeepUnwrap<T> = T extends Promise<infer U> ? DeepUnwrap<U> : T;
type Test10 = DeepUnwrap<Promise<Promise<string>>>; // string

Как отвечать на собеседовании

Начни с чёткого определения: infer - это ключевое слово для вывода типа внутри условного типа. Приведи простой пример с массивом или функцией. Объясни ограничения (только в extends, только одна позиция на один infer). Покажи практическое применение: ReturnType, Parameters, собственные утилиты. Если спросят про сложные случаи - расскажи про инвариантность, ковариантность и контрвариантность в контексте infer (например, почему infer в параметрах функции работает контрвариантно). Упомяни, что infer - это основа для построения type-level programming в TypeScript.

Что проверяет интервьюер

  • Понимание условных типов и pattern matching на уровне типов.
  • Умение читать и писать сложные type helpers.
  • Знание стандартных утилитарных типов и их реализации.
  • Понимание ограничений infer (только в extends, область видимости).
  • Способность объяснить, как TypeScript выводит типы в разных контекстах (функции, массивы, промисы).
  • Глубокое понимание системы типов TypeScript (вариантность, распределительные условные типы).

Типичные ошибки

  • Использование infer вне условного типа (синтаксическая ошибка).
  • Попытка использовать infer в нескольких позициях без необходимости (можно, но нужно понимать порядок вывода).
  • Путаница между infer и typeof - infer работает на уровне типов, typeof - на уровне значений.
  • Неправильное понимание области видимости: переменная infer доступна только в ветках true/false данного условного типа.
  • Игнорирование распределительного поведения условных типов с union (например, ArrayItem<string | number[]> даст string | number, а не string | number[]).
  • Попытка вывести тип, который не может быть выведен из-за инвариантности (например, Set<T> - infer не сработает, так как Set инвариантен по T).

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью