TypeScript: утилитарные типы для работы с данными
Использование встроенных утилитарных типов TypeScript: Partial, Pick, Omit, Required, Readonly для трансформации типов без дублирования кода.
TypeScript предоставляет встроенные утилитарные типы для трансформации существующих типов. Это избавляет от дублирования кода.
Partial — все поля опциональны
interface User {
id: number;
name: string;
email: string;
password: string;
createdAt: Date;
}
// Partial делает все поля опциональными
type PartialUser = Partial<User>;
// Можно обновить только нужные поля
const updateData: PartialUser = {
name: "New Name" // можно указать только нужные поля
};
// Использование в функции обновления
function updateUser(id: number, data: Partial<User>): void {
// Обновляем только переданные поля
}
Pick — выбрать только нужные поля
// Выбираем только id, name и email
type PublicUser = Pick<User, "id" | "name" | "email">;
const publicProfile: PublicUser = {
id: 1,
name: "John",
email: "john@example.com"
// password и createdAt недоступны
};
// Использование для API-ответов
function getUserPublic(id: number): Promise<PublicUser> {
// Возвращаем только публичные данные
}
Omit — исключить ненужные поля
// Исключаем password из типа
type UserWithoutPassword = Omit<User, "password">;
const safeUser: UserWithoutPassword = {
id: 1,
name: "John",
email: "john@example.com",
createdAt: new Date()
// password недоступен
};
// Можно исключить несколько полей
type UserPublic = Omit<User, "password" | "createdAt">;
Required — все поля обязательны
interface Config {
host?: string;
port?: number;
timeout?: number;
}
// Required делает все поля обязательными
type RequiredConfig = Required<Config>;
const config: RequiredConfig = {
host: "localhost", // обязательно
port: 3000, // обязательно
timeout: 5000 // обязательно
};
Readonly — сделать поля только для чтения
// Все поля становятся readonly
type ReadonlyUser = Readonly<User>;
const user: ReadonlyUser = {
id: 1,
name: "John",
email: "john@example.com",
password: "secret",
createdAt: new Date()
};
// user.name = "Jane"; // ❌ Ошибка: нельзя изменить readonly поле
Комбинирование утилитарных типов
// Публичный профиль без пароля и даты создания, только для чтения
type PublicReadonlyUser = Readonly<Omit<User, "password" | "createdAt">>;
// Частичное обновление с обязательными полями
type UserUpdate = Partial<Pick<User, "name" | "email">> & {
id: number; // id обязателен
};
Record — создание типа из ключей и значений
// Record<K, V> создаёт объект с ключами типа K и значениями типа V
type StatusMap = Record<string, "pending" | "approved" | "rejected">;
const statuses: StatusMap = {
user1: "pending",
user2: "approved",
user3: "rejected"
};
// С конкретными ключами
type UserRoles = Record<"admin" | "user" | "guest", string[]>;
Extract и Exclude — работа с union типами
type Status = "pending" | "approved" | "rejected" | "spam";
// Extract — выбрать только определённые типы
type ActiveStatus = Extract<Status, "pending" | "approved">; // "pending" | "approved"
// Exclude — исключить определённые типы
type CleanStatus = Exclude<Status, "spam">; // "pending" | "approved" | "rejected"
NonNullable — исключить null и undefined
type MaybeString = string | null | undefined;
// NonNullable исключает null и undefined
type DefiniteString = NonNullable<MaybeString>; // string
function processString(str: NonNullable<string | null>): void {
// str гарантированно string, не null
}
Usage:
Используй утилитарные типы вместо создания новых интерфейсов для похожих структур. Это уменьшает дублирование и упрощает поддержку кода.
Notes:
⚠️ Утилитарные типы работают только на этапе компиляции. В рантайме они не существуют. Комбинируй несколько утилитарных типов для создания сложных трансформаций. Всегда документируй назначение производных типов.