Динамічні ключі об'єкта
1. Використати індексну сигнатуру (index signature)
Це найбазовіший і найпоширеніший спосіб.
interface Dictionary {
[key: string]: string;
}
const colors: Dictionary = {
red: "#ff0000",
green: "#00ff00",
blue: "#0000ff",
};Тут
[key: string]: stringозначає: об'єкт може мати будь-яку кількість властивостей із ключами типуstring, і всі значення мають бути рядками.
Варіанти індексних сигнатур
| Сигнатура | Що означає |
|---|---|
[key: string]: string | ключі - рядки, значення - рядки |
[key: number]: boolean | ключі - числа, значення - булеві |
[key: string]: any | ключі - будь-які рядки, значення - будь-якого типу |
[key: string]: SomeType | значення відповідають користувацькому типу |
Приклад з користувацьким типом
interface UserScores {
[username: string]: number;
}
const scores: UserScores = {
Tim: 90,
Max: 75,
John: 82,
};TypeScript перевірить, що всі значення - числа.
2. Використати узагальнений тип (generic) з Record
TypeScript надає утилітний тип Record<K, T> -
зручний спосіб описати об'єкти з динамічними ключами певного типу.
type Dictionary = Record<string, string>;
const translations: Dictionary = {
hello: "Hola",
bye: "Adios",
};
Record<K, T>буквально означає: "об'єкт, де кожен ключ має типK, а значення - типT".
Приклад: типізовані ключі
type Languages = "en" | "fr" | "de";
type LocaleMap = Record<Languages, string>;
const appName: LocaleMap = {
en: "Shop",
fr: "Boutique",
de: "Geschaft",
};TypeScript гарантує, що будуть усі три ключі (
en,fr,de), і що інших бути не може.
3. Опис об'єкта з динамічними ключами і додатковими полями
Можна комбінувати конкретні властивості з індексною сигнатурою.
interface ProductInfo {
id: number;
name: string;
[extraField: string]: string | number;
}
const product: ProductInfo = {
id: 10,
name: "Shirt",
color: "white",
price: 49,
};TypeScript дозволяє додавати будь-які поля, але значення повинні бути string або number (за індексною сигнатурою).
4. Динамічні ключі, обчислені з типу
TypeScript вміє створювати об'єкти з ключами, виведеними з union-типу:
type Status = "loading" | "success" | "error";
type StatusMessages = {
[K in Status]: string;
};
const messages: StatusMessages = {
loading: "Loading...",
success: "Success!",
error: "Error!",
};Тут використовується mapped type - TypeScript генерує об'єкт із ключами
"loading" | "success" | "error"і значеннями типуstring.
5. Якщо потрібні часткові (необов'язкові) динамічні ключі
Можна додати Partial<>:
type FeatureFlags = Partial<Record<"darkMode" | "beta" | "ads", boolean>>;
const flags: FeatureFlags = {
darkMode: true, // можна
// інші ключі можна не вказувати
};6. Різниця між Record і індексною сигнатурою
| Властивість | Record | Індексна сигнатура |
|---|---|---|
| Ключі строго типізовані | Так | Ні (будь-які рядки) |
| Можна обмежити конкретними ключами | Так | Ні |
| Можна комбінувати з конкретними властивостями | Складніше | Легко |
| Зручний для "словникових/enum" структур | Так | Іноді |
7. Приклад із реального життя
Словник перекладів
type Locale = "en" | "fr" | "de";
interface Translations {
[key: string]: Record<Locale, string>;
}
const ui: Translations = {
login: { en: "Login", fr: "Connexion", de: "Anmelden" },
logout: { en: "Logout", fr: "Deconnexion", de: "Abmelden" },
};Підсумок
У TypeScript об'єкт з динамічними ключами можна описати кількома способами:
| Сценарій | Рішення | Приклад |
|---|---|---|
| Будь-які ключі і значення | Індексна сигнатура | [key: string]: string |
| Ключі обмежені типом | Record<K, T> | `Record<"en" |
| Ключі формуються з union-типу | Mapped Type | [K in Status]: string |
| Усі поля опціональні | Partial + Record | Partial<Record<K, T>> |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.