> Как типизировать объект с разными ключами и значениями в TypeScript? (TypeScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Инрэко, КИТМЕД
Стек: TypeScript
> Пример ответа
Короткий ответ
Для типизации объекта с разными ключами и значениями в TypeScript используют index signature: { [key: string]: number }. Если ключи заранее известны, применяют mapped types: { [K in 'a' | 'b']: string }. Для смешанных типов значений - union в index signature или Record с discriminated union. При необходимости точной типизации каждого ключа - interface с конкретными полями.
Подробное объяснение
TypeScript предоставляет несколько подходов в зависимости от сценария:
-
Index signature - когда ключи неизвестны заранее, но все значения одного типа:
TYPESCRIPTinterface StringMap {[key: string]: string;} -
Mapped types - когда ключи известны, а значения могут быть разными:
TYPESCRIPTtype Config = {[K in 'host' | 'port' | 'ssl']: K extends 'port' ? number : string;}; -
Record<K, V> - утилитарный тип для однотипных значений:
TYPESCRIPTtype UserRoles = Record<'admin' | 'user', string>; -
Union в значении - если значения разных типов:
TYPESCRIPTinterface MixedMap {[key: string]: string | number | boolean;} -
Discriminated union - для строгой типизации каждого ключа:
TYPESCRIPTtype Schema = {name: string;age: number;active: boolean;};
Важно: index signature с string ключом конфликтует с конкретными полями другого типа - нужно использовать intersection или mapped types.
На практике
В реальных проектах чаще всего встречаются:
- API responses - используют
Record<string, unknown>с последующей валидацией (zod, io-ts) - Configuration objects - конкретные интерфейсы с optional полями
- Dynamic forms - mapped types с conditional types для разных типов полей
- Event maps -
Record<EventName, Handler>с discriminated union
Для сложных случаев применяют generic constraints:
TYPESCRIPTfunction createStore<T extends Record<string, unknown>>(initial: T) {// ...}
Пример кода
TYPESCRIPT// Index signature для динамических ключейinterface Dictionary<T> {[key: string]: T;}const dict: Dictionary<number> = { a: 1, b: 2 };// Mapped type для известных ключей с разными типамиtype FormState = {[K in 'email' | 'password' | 'remember']:K extends 'remember' ? boolean : string;};// Record с union типомtype StatusMap = Record<'pending' | 'success' | 'error', string>;// Смешанный объект с конкретными полямиinterface UserProfile {id: number;name: string;metadata: Record<string, unknown>;tags: string[];}// Generic helper для типизации динамических объектовtype TypedObject<K extends string, V> = {[P in K]: V;};
Как отвечать на собеседовании
Начни с index signature как базового решения, затем упомяни mapped types для известных ключей. Объясни trade-off между гибкостью и типобезопасностью. Приведи пример из реального проекта - например, типизацию конфига или ответа API. Покажи понимание ограничений: index signature не работает с конкретными полями другого типа. Упомяни альтернативы вроде Partial, Pick, Omit для сложных сценариев.
Что проверяет интервьюер
- Понимание разницы между index signature и mapped types
- Умение выбирать правильный подход под задачу
- Знание ограничений TypeScript (например, конфликт index signature с конкретными полями)
- Способность типизировать реальные сценарии (API, конфиги, формы)
- Понимание trade-off между строгостью типов и гибкостью
Типичные ошибки
- Использование
anyвместоunknownдля неизвестных значений - Попытка добавить конкретное поле с другим типом в объект с index signature
- Игнорирование
readonlyдля иммутабельных объектов - Злоупотребление
Record<string, any>вместо более точных типов - Неправильное использование conditional types в mapped types
- Забывание про
keyofдля динамической работы с ключами
> Похожие задачи по frontend
Что такое операторы Pick, Partial, Omit, Required, NonNullable и Exclude в TypeScript
Как работают type guards в TypeScript
Можно ли объединить несколько типов в один тип в TypeScript и как это сделать?
Какие альтернативы использованию infer в TypeScript для типизации ключей?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью