Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Для чего нужен Record?
Record<K, T> — это встроенный TypeScript тип, который создаёт объект с ключами определённого типа и значениями определённого типа. Это очень полезный утилитарный тип для создания типизированных словарей, объектов с предопределённой структурой и мап-структур.
Синтаксис
type Record<K extends string | number | symbol, T> = { [P in K]: T }
Это означает: создать объект, где ключи должны быть типа K, а значения — типа T.
Базовый пример
// Задаём, какие ключи допустимы и какой тип значений
type UserRoles = Record<'admin' | 'user' | 'guest', string>;
// Это эквивалентно:
type UserRoles = {
admin: string;
user: string;
guest: string;
};
// Использование
const roles: UserRoles = {
admin: 'Administrator',
user: 'Regular User',
guest: 'Guest'
};
Практические примеры
Пример 1: Конфигурация по ролям
type UserRole = 'admin' | 'moderator' | 'user';
type Permissions = 'read' | 'write' | 'delete';
// Определяем, какие разрешения есть у каждой роли
const rolePermissions: Record<UserRole, Permissions[]> = {
admin: ['read', 'write', 'delete'],
moderator: ['read', 'write'],
user: ['read']
};
// Использование
function canDelete(role: UserRole): boolean {
return rolePermissions[role].includes('delete');
}
console.log(canDelete('admin')); // true
console.log(canDelete('user')); // false
Пример 2: Переводы на разные языки
type Language = 'en' | 'ru' | 'de';
// Объект переводов
const translations: Record<Language, Record<string, string>> = {
en: {
hello: 'Hello',
goodbye: 'Goodbye'
},
ru: {
hello: 'Привет',
goodbye: 'До свидания'
},
de: {
hello: 'Hallo',
goodbye: 'Auf Wiedersehen'
}
};
// Использование
function getMessage(lang: Language, key: string): string {
return translations[lang][key];
}
console.log(getMessage('ru', 'hello')); // 'Привет'
Пример 3: Статус-коды HTTP
type HttpStatus = 200 | 201 | 400 | 401 | 404 | 500;
const httpMessages: Record<HttpStatus, string> = {
200: 'OK',
201: 'Created',
400: 'Bad Request',
401: 'Unauthorized',
404: 'Not Found',
500: 'Internal Server Error'
};
// Использование
function getStatusMessage(code: HttpStatus): string {
return httpMessages[code];
}
console.log(getStatusMessage(404)); // 'Not Found'
Пример 4: Валидаторы для полей формы
type FieldName = 'email' | 'password' | 'name' | 'age';
type Validator = (value: string) => boolean;
const fieldValidators: Record<FieldName, Validator> = {
email: (value) => /^[^@]+@[^@]+\.[^@]+$/.test(value),
password: (value) => value.length >= 8,
name: (value) => value.length >= 2,
age: (value) => /^\d+$/.test(value) && parseInt(value) >= 18
};
// Использование
function validateField(fieldName: FieldName, value: string): boolean {
return fieldValidators[fieldName](value);
}
console.log(validateField('email', 'user@example.com')); // true
console.log(validateField('password', '123')); // false
console.log(validateField('age', '25')); // true
Record с enum
enum Color {
Red = 'red',
Green = 'green',
Blue = 'blue'
}
type ColorHex = Record<Color, string>;
const colorMap: ColorHex = {
[Color.Red]: '#FF0000',
[Color.Green]: '#00FF00',
[Color.Blue]: '#0000FF'
};
console.log(colorMap[Color.Red]); // '#FF0000'
Record vs интерфейс
// Вариант 1: Record (более краткий)
type UserStats = Record<'likes' | 'comments' | 'shares', number>;
// Вариант 2: Interface (более детальный)
interface UserStatsInterface {
likes: number;
comments: number;
shares: number;
}
// Record лучше, когда ключи динамичные или из типа/enum
type StatusCode = 200 | 404 | 500;
type StatusMessages = Record<StatusCode, string>;
// Interface лучше для больших объектов с методами
interface ApiClient {
get(url: string): Promise<any>;
post(url: string, data: any): Promise<any>;
}
Record с readonly
type ReadonlyConfig = Readonly<Record<'apiUrl' | 'timeout' | 'retries', string | number>>;
const config: ReadonlyConfig = {
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3
};
// config.timeout = 10000; // Ошибка: Cannot assign to readonly property
Record с Partial (опциональные значения)
type Settings = Partial<Record<'theme' | 'fontSize' | 'notifications', string>>;
const userSettings: Settings = {
theme: 'dark'
// fontSize и notifications необязательны
};
Практический пример из React
import { useState } from 'react';
type TabName = 'profile' | 'settings' | 'notifications';
interface TabContent {
title: string;
icon: string;
}
const tabConfig: Record<TabName, TabContent> = {
profile: {
title: 'Профиль',
icon: 'user'
},
settings: {
title: 'Настройки',
icon: 'gear'
},
notifications: {
title: 'Уведомления',
icon: 'bell'
}
};
function TabPanel() {
const [activeTab, setActiveTab] = useState<TabName>('profile');
return (
<div>
{Object.entries(tabConfig).map(([tab, { title, icon }]) => (
<button
key={tab}
onClick={() => setActiveTab(tab as TabName)}
className={activeTab === tab ? 'active' : ''}
>
{icon} {title}
</button>
))}
<div>
{tabConfig[activeTab].title} content here
</div>
</div>
);
}
Итог
Record<K, T> — это полезный TypeScript тип для:
- Создания типизированных объектов-словарей
- Определения мап между ключами и значениями
- Конфигураций, где ключи известны заранее
- Трансформации типов и enum-ов в объекты
- Обеспечения типобезопасности при работе с динамическими ключами
Rec используется часто в реальных проектах для конфигураций, переводов, валидаторов и других словарь-подобных структур.