Как создать пару "ключ-значение" (key-value pair) в TypeScript?
TypeScript и пары "ключ-значение": основные подходы
В TypeScript нет специального встроенного типа KeyValuePair как отдельной сущности, но есть несколько мощных способов работы с такими структурами. Всё зависит от того, что именно вы хотите сделать: сохранить динамический объект, массив кортежей или использовать строгую типизацию для конкретных ключей.
1. Массив кортежей (Tuple) — самый простой способ
Если вам нужна именно пара "ключ-значение" как элемент массива, используйте кортеж (tuple) TypeScript:
// Явно задаём тип: [ключ: string, значение: number]
const pair: [string, number] = ["age", 30];
// Массив таких пар
const pairs: [string, number][] = [
["age", 30],
["height", 175]
];
2. Динамический объект с Record<K, V>
Для случая, когда вы хотите создать объект с динамическими ключами, используйте встроенный тип Record<Keys, Type>. Это идеально подходит для вашей функции buildObject:
function buildObject<T extends string, U>(pairs: [T, U][]): Record<T, U> {
const result = {} as Record<T, U>;
for (const [key, value] of pairs) {
result[key] = value;
}
return result;
}
// Использование
const obj = buildObject([
["name", "Анна"],
["age", 30],
["city", "Москва"]
]);
// Тип obj: Record<"name" | "age" | "city", string | number>
Обратите внимание на as Record<T, U> — это приведение типа, необходимое, потому что пустой объект TypeScript не может вывести как Record. Дженерики T extends string и U позволяют сохранить точные типы ключей и значений.
3. Интерфейс для конкретных пар
Если ключи известны заранее, лучше создать интерфейс с конкретными полями:
interface User {
name: string;
age: number;
city: string;
}
const user: User = {
name: "Анна",
age: 30,
city: "Москва"
};
Это даёт строгую проверку типов и автодополнение в IDE.
4. Тип Map — для сложных ключей
Если ключи не являются строками или числами, или вам нужны методы вроде .get() и .set(), используйте встроенный объект Map:
const userMap = new Map<string, any>();
userMap.set("name", "Анна");
userMap.set("age", 30);
// Или с типизированными значениями
const typedMap = new Map<string, string | number>();
typedMap.set("name", "Анна");
typedMap.set("age", 30);
5. Свой тип KeyValuePair (кастомный)
Вы можете создать свой обобщённый тип для пары:
type KeyValuePair<K extends string | number | symbol, V> = {
key: K;
value: V;
};
// Использование
const pair: KeyValuePair<"age", number> = {
key: "age",
value: 30
};
Но этот подход менее удобен, чем кортежи, так как требует дополнительной вложенности.
Рекомендация
- Для динамических объектов — используйте
Record<K, V>. - Для массива пар — кортежи
[K, V][]. - Для строго известных ключей — интерфейс с конкретными полями.
- Для сложных ключей —
Map<K, V>.
Выберите подход, который лучше всего подходит под вашу задачу. TypeScript даёт гибкость, но лучше всего использовать наиболее строгий тип, который отражает вашу предметную область.
<<Альтернативный подход: индексная сигнатура и утилитарные типы
Если вы хотите сохранить максимальную гибкость, но при этом избежать any, используйте индексную сигнатуру с ограничениями:
interface FlexibleObject {
[key: string]: string | number | boolean;
}
const data: FlexibleObject = {
name: "Анна",
age: 30,
isActive: true
};
Этот подход позволяет добавлять любые строковые ключи, но значения должны быть одного из перечисленных типов. Недостаток — все ключи считаются строками, даже если вы используете числа.
Для более точного контроля можно использовать утилитарный тип Partial<T> в комбинации с конкретным интерфейсом:
interface UserFields {
name: string;
age: number;
city?: string;
}
// Частичная реализация
const partialUser: Partial<UserFields> = {
name: "Анна"
};
Этот способ хорош, когда вы знаете возможные ключи, но не все они обязательны. TypeScript сам подскажет, какие поля доступны, и не даст добавить лишние.
Ещё один полезный приём — использовать typeof для вывода типа из существующего объекта:
const example = { name: "Анна", age: 30 };
type ExampleType = typeof example; // { name: string; age: number; }
Это может пригодиться, когда вы создаёте объект в одном месте, а потом хотите типизировать похожие структуры в другом.
Ответов пока нет.
Войдите чтобы оставить ответ