← Назад к вопросам
Встречал ли описание объекта в TypeScript через утилиту Record
2.0 Middle🔥 102 комментариев
#TypeScript
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
TypeScript Record: Описание объектов
Record — это утилита типов TypeScript для создания объектов с предопределённым набором ключей и типом значений. Это мощный и часто используемый инструмент в реальных проектах.
Базовое использование
Record<Keys, ValueType> принимает два параметра:
- Keys — допустимые ключи объекта
- ValueType — тип значений для всех ключей
// Описываем объект с фиксированными ключами
type StatusColors = Record<'success' | 'error' | 'warning' | 'info', string>;
const colors: StatusColors = {
success: '#22c55e',
error: '#ef4444',
warning: '#f59e0b',
info: '#3b82f6'
// missing: '#000' // ошибка TypeScript — не хватает ключей
};
Типизация гарантирует:
- Ровно эти ключи — не меньше и не больше
- Каждый ключ имеет значение нужного типа
Практические примеры
1. Конфигурация по профессиям
type Profession = 'frontend' | 'backend' | 'devops' | 'qa';
type ProfessionConfig = Record<Profession, {
icon: string;
description: string;
difficulty: number;
}>;
const professions: ProfessionConfig = {
frontend: {
icon: 'react',
description: 'React, TypeScript, CSS',
difficulty: 7
},
backend: {
icon: 'python',
description: 'Python, FastAPI, PostgreSQL',
difficulty: 8
},
devops: {
icon: 'docker',
description: 'Docker, Kubernetes, CI/CD',
difficulty: 9
},
qa: {
icon: 'pytest',
description: 'Testing, Automation',
difficulty: 6
}
};
// Использование
const frontendConfig = professions.frontend; // есть автодополнение
const allProfessions = Object.keys(professions) as Profession[];
2. Маппирование статусов
type QuestionStatus = 'pending' | 'solved' | 'skipped' | 'failed';
const statusMessages: Record<QuestionStatus, string> = {
pending: 'Ожидание ответа',
solved: 'Решено правильно',
skipped: 'Пропущено',
failed: 'Ошибка в ответе'
};
const statusStyles: Record<QuestionStatus, string> = {
pending: 'text-gray-500',
solved: 'text-green-500',
skipped: 'text-yellow-500',
failed: 'text-red-500'
};
// Использование
function getStatusDisplay(status: QuestionStatus) {
return {
message: statusMessages[status],
className: statusStyles[status]
};
}
3. HTTP методы и их свойства
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
const methodProperties: Record<HttpMethod, {
hasBody: boolean;
isSafe: boolean;
isIdempotent: boolean;
}> = {
GET: { hasBody: false, isSafe: true, isIdempotent: true },
POST: { hasBody: true, isSafe: false, isIdempotent: false },
PUT: { hasBody: true, isSafe: false, isIdempotent: true },
DELETE: { hasBody: false, isSafe: false, isIdempotent: true },
PATCH: { hasBody: true, isSafe: false, isIdempotent: false }
};
// Компилятор проверит, что все методы описаны
Record vs Interface vs Type Literal
// 1. Через Record
type StatusRecord = Record<'active' | 'inactive', boolean>;
const record: StatusRecord = { active: true, inactive: false };
// 2. Через Interface
interface StatusInterface {
active: boolean;
inactive: boolean;
}
const iface: StatusInterface = { active: true, inactive: false };
// 3. Через Type Literal
type StatusLiteral = { active: boolean; inactive: boolean };
const literal: StatusLiteral = { active: true, inactive: false };
Различия:
| Способ | Плюсы | Минусы |
|---|---|---|
| Record | Легко масштабировать список ключей, можно программировать | Сложнее читать для больших структур |
| Interface | Классическая типизация, расширяемость | Нужно писать каждый ключ |
| Type Literal | Простотой и прозрачностью | Дублирование при много ключей |
Динамические ключи из массива
// Если ключи приходят из переменной
const professionList = ['frontend', 'backend', 'devops'] as const;
type ProfessionKey = typeof professionList[number]; // 'frontend' | 'backend' | 'devops'
const configs: Record<ProfessionKey, { level: number }> = {
frontend: { level: 7 },
backend: { level: 8 },
devops: { level: 9 }
};
Record с индексными сигнатурами
// Record для любого строкового ключа
type StringMap = Record<string, number>;
const scores: StringMap = {
alice: 95,
bob: 87,
charlie: 92
};
scores.newUser = 100; // OK
// Record с ограничением на ключи
type NumericKeys = Record<number, string>;
const descriptions: NumericKeys = {
1: 'First',
2: 'Second',
3: 'Third'
};
Вложенные Record
type UserRole = 'admin' | 'user' | 'guest';
type Permission = 'read' | 'write' | 'delete';
type RolePermissions = Record<UserRole, Record<Permission, boolean>>;
const permissions: RolePermissions = {
admin: {
read: true,
write: true,
delete: true
},
user: {
read: true,
write: true,
delete: false
},
guest: {
read: true,
write: false,
delete: false
}
};
// Использование
const canUserDelete = permissions.user.delete; // false
Реальный пример: Форма с валидацией
type FormField = 'email' | 'password' | 'name';
type FormErrors = Record<FormField, string>;
type FormValues = Record<FormField, string>;
type FieldValidators = Record<FormField, (value: string) => boolean>;
const validators: FieldValidators = {
email: (val) => val.includes('@'),
password: (val) => val.length >= 8,
name: (val) => val.length > 0
};
const values: FormValues = {
email: 'user@example.com',
password: 'password123',
name: 'John'
};
const errors: FormErrors = {
email: '',
password: '',
name: ''
};
// Валидируем форму
(Object.keys(validators) as FormField[]).forEach(field => {
if (!validators[field](values[field])) {
errors[field] = `Invalid ${field}`;
}
});
Производство: Кэширование результатов
type CacheKey = 'questions' | 'professions' | 'interview';
type Cache = Record<CacheKey, {
data: any;
timestamp: number;
ttl: number;
}>;
const cache: Cache = {
questions: { data: [], timestamp: Date.now(), ttl: 3600000 },
professions: { data: [], timestamp: Date.now(), ttl: 7200000 },
interview: { data: null, timestamp: 0, ttl: 1800000 }
};
// Функция для проверки валидности кэша
function isCacheValid(key: CacheKey): boolean {
const entry = cache[key];
return Date.now() - entry.timestamp < entry.ttl;
}
Когда использовать Record
Используй Record когда:
- Нужно описать объект с фиксированным набором ключей
- Все значения имеют одинаковый тип (или объединение типов)
- Ключи удобно выражаются через union type
- Нужна масштабируемость — добавляешь новый ключ в union, и TypeScript требует добавить его везде
Используй Interface когда:
- Ключи разнотипные (разные типы значений)
- Нужна расширяемость через наследование
- Объект может быть частично заполнен (optional properties)
// Хорошо для Record
type StatusColors = Record<'success' | 'error' | 'warning', string>;
// Лучше для Interface
interface User {
id: string;
name: string;
email: string;
age?: number;
}
Вывод
Record — это мощный инструмент TypeScript для создания объектов с предопределённым набором ключей. Он особенно полезен для конфигураций, маппингов и любых структур, где ключи можно выразить как union type. Правильное использование Record улучшает типизацию и предотвращает опечатки.