> Какие альтернативы использованию infer в TypeScript для типизации ключей? (TypeScript)

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

Компании: RecruitTech

Стек: TypeScript

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

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

infer в TypeScript используется для извлечения типов из условных типов. Для типизации ключей без infer можно использовать keyof, mapped types с in и as, а также Extract и Exclude для фильтрации ключей. Для работы с значениями по ключам подойдут Indexed Access Types (T[K]). infer незаменим только при необходимости вывести тип из сложной структуры, например, из типа функции или Promise.

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

infer - это мощный инструмент для вывода типов внутри условных типов, но для типизации ключей часто можно обойтись без него. Основные альтернативы:

  1. keyof - получает объединение всех ключей объекта:

    TYPESCRIPT
    type Keys = keyof { a: number; b: string }; // 'a' | 'b'
  2. Mapped types с in и as - позволяют трансформировать ключи:

    TYPESCRIPT
    type Prefixed<T> = { [K in keyof T as `prefix_${string & K}`]: T[K] }
  3. Extract и Exclude - фильтруют ключи по условию:

    TYPESCRIPT
    type StringKeys<T> = Extract<keyof T, string>
  4. Indexed Access Types - получают тип значения по ключу:

    TYPESCRIPT
    type Value = SomeType['key']
  5. Conditional types с проверкой extends - для сложной логики без infer:

    TYPESCRIPT
    type IsStringKey<T, K> = K extends keyof T ? (T[K] extends string ? K : never) : never

infer становится необходимым, когда нужно извлечь внутренний тип из обёртки (например, тип элемента массива из Array<T> или возвращаемый тип функции).

На практике

Для типизации ключей в реальных проектах чаще всего достаточно комбинации keyof и mapped types. infer обычно применяется в библиотечных утилитах (типа ReturnType, Parameters) или при работе с дженериками высшего порядка.

Примеры практического использования без infer:

  • Получение всех строковых ключей: type StringKeys<T> = Extract<keyof T, string>
  • Создание типа с префиксами ключей: type PrefixedKeys<T> = { [K in keyof T as get${Capitalize<string & K>}]: T[K] }
  • Фильтрация ключей по типу значения: type NumericKeys<T> = { [K in keyof T]: T[K] extends number ? K : never }[keyof T]

Пример кода

TYPESCRIPT
interface User {
id: number;
name: string;
email: string;
age: number;
}
// Без infer: получаем ключи со строковыми значениями
type StringValueKeys<T> = {
[K in keyof T]: T[K] extends string ? K : never
}[keyof T];
type UserStringKeys = StringValueKeys<User>; // "name" | "email"
// С infer: аналогичный результат, но с избыточным использованием infer
type StringValueKeysWithInfer<T> = T extends { [K in keyof T]: infer V }
? { [K in keyof T]: V extends string ? K : never }[keyof T]
: never;
// Более сложный пример: получение ключей, где значение - массив
type ArrayKeys<T> = {
[K in keyof T]: T[K] extends any[] ? K : never
}[keyof T];
type UserArrayKeys = ArrayKeys<User>; // never (в User нет массивов)

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

Начните с чёткого разделения: infer - для вывода типов из сложных структур, а для работы с ключами есть специализированные инструменты. Приведите 2-3 альтернативы с примерами. Подчеркните, что infer не является основным инструментом для типизации ключей - это скорее исключение для продвинутых сценариев. Упомяните trade-off: infer делает код менее читаемым, поэтому его стоит использовать только когда другие подходы не работают.

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

  • Понимание разницы между выводом типов (infer) и прямым доступом к ключам (keyof)
  • Знание mapped types и условных типов
  • Умение выбирать правильный инструмент под задачу
  • Понимание, когда infer действительно необходим, а когда это избыточно
  • Способность объяснить trade-off между выразительностью и читаемостью кода

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

  • Попытка использовать infer там, где достаточно keyof или mapped types
  • Непонимание, что infer работает только внутри conditional types с extends
  • Использование infer для простых случаев, что усложняет код без необходимости
  • Путаница между infer для ключей и infer для значений
  • Игнорирование встроенных утилит (Extract, Exclude) в пользу ручных конструкций с infer

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

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