ProgrammazioneFullstack разработчик

Что такое keyof typeof в TypeScript? Как работает их сочетание и где применяется на практике?

Supera i colloqui con l'assistente IA Hintsage

Ответ.

Операторы keyof и typeof — мощные инструменты типизации TypeScript. Их совместное использование позволяет строить типы на лету, создавать безопасные функции и выражать структуру объектов максимально гибко.

История вопроса

typeof в TypeScript служит для выведения типа по переменной, а keyof возвращает union всех ключей объекта или типа. В связке они позволяют работать с динамически объявленными объектами и делать взаимосвязанные типы.

Проблема

Без этих операторов при работе с объектами, enums, и таблицами соответствия часто приходится вручную повторять строки ключей в типах и значениях, что ведёт к ошибкам рассинхронизации и усложняет поддержку кода.

Решение

С помощью typeof получают тип из значения переменной, а с помощью keyof строят тип объединения всех её ключей. Итог — автоматизация типизации.

Пример кода:

const ERRORS = { NOT_FOUND: 'Not found', UNAUTHORIZED: 'Unauthorized', SERVER_ERROR: 'Server error', }; // Через typeof получаем тип, а через keyof — все ключи объекта function getErrorMessage(code: keyof typeof ERRORS): string { return ERRORS[code]; }

Ключевые особенности:

  • Помогает строить строго связанные типы key-value без ручного обновления.
  • Позволяет типизировать функции, работающие с ключами объектов.
  • Устраняет проблемы с рассинхронизацией между ключами и типами.

Вопросы с подвохом.

Могут ли значения объекта, полученные через typeof, автоматически стать ключами в union-типе?

Нет, typeof возвращает тип структуры объекта, а не значения. Чтобы получить union значений, нужно отдельно получить типы значений.

Что вернёт typeof для enum и что вернет keyof typeof для enum?

Для enum typeof возвращает тип объекта enum (с обоими направлениями: key-value и value-key), а keyof typeof даёт union строковых/числовых ключей этого объекта. Например:

enum Colors { Red = 'R', Blue = 'B' } type ColorKeys = keyof typeof Colors; // 'Red' | 'Blue'

Можно ли с помощью keyof typeof получить type-safe список всех возможных параметров функции, которая принимает ключи объекта?

Да, таким образом вы создаёте функцию, принимающую только допустимые ключи. Это предотвращает ошибки при работе с ключами объектов.

const config = { mode: 'dark', lang: 'ru' }; type ConfigKeys = keyof typeof config; // 'mode' | 'lang' function useConfig(key: ConfigKeys) { // ... }

Типовые ошибки и анти-паттерны

  • Ошибочное ожидание, что keyof typeof применим к значениям массива — для массива это индексы, а не значения.
  • Непонимание, что typeof работает на уровне типов, а не возвращает runtime-значение.
  • Применение к типу, не объявленному явно, что ломает вывод типов.

Пример из жизни

Негативный кейс

В константе со статусами API вручную прописывают типы строковых ключей:

type StatusCodes = 'OK' | 'FAIL' | 'PENDING'; function isKnownStatus(code: StatusCodes) { /* ... */ }

Плюсы:

  • Ясно видно, какие строки допустимы.

Минусы:

  • Необходимо вручную менять типы при обновлении списка; рассинхронизация и ошибки.

Позитивный кейс

Использование keyof typeof для автоматической поддержки списка:

const STATUS = { OK: 1, FAIL: 0, PENDING: 2 }; type StatusKeys = keyof typeof STATUS; function checkStatus(key: StatusKeys) { /* ... */ }

Плюсы:

  • При добавлении/удалении статуса тип автоматически обновится.
  • Нет рассинхронизации типов и значений.

Минусы:

  • При работе с очень сложными структурами понимание этих типов требует опыта и внимания.