Что такое utility types в TypeScript?

MiddleTypeScript · Frontend·Обновлено 24 июня 2026
Коротко
Utility types — это встроенные универсальные типы TypeScript, которые позволяют трансформировать существующие типы: делать их опциональными, только для чтения, частичными или выбирать/исключать отдельные ключи.

Utility Types в TypeScript

Utility types — встроенные вспомогательные типы, реализованные через дженерики. Они позволяют создавать новые типы на основе существующих без дублирования кода.

Основные utility types

Partial<T> — делает все поля типа необязательными:

interface User {
  id: number;
  name: string;
  email: string;
}

// Все поля становятся опциональными
type PartialUser = Partial<User>;
// { id?: number; name?: string; email?: string }

Required<T> — противоположность Partial, делает все поля обязательными.

Readonly<T> — запрещает изменение полей после создания объекта:

const config: Readonly<User> = { id: 1, name: 'Иван', email: 'i@i.ru' };
config.name = 'Пётр'; // Ошибка: нельзя изменить readonly свойство

Pick<T, K> — выбирает только указанные ключи из типа:

type UserPreview = Pick<User, 'id' | 'name'>;
// { id: number; name: string }

Omit<T, K> — исключает указанные ключи из типа:

type UserWithoutEmail = Omit<User, 'email'>;
// { id: number; name: string }

Record<K, V> — создаёт тип объекта с ключами K и значениями V:

type RoleMap = Record<'admin' | 'user' | 'guest', boolean>;
// { admin: boolean; user: boolean; guest: boolean }

Exclude<T, U> и Extract<T, U> — работают с union-типами:

type Status = 'active' | 'inactive' | 'banned';

type ActiveStatus = Exclude<Status, 'banned'>;
// 'active' | 'inactive'

type BannedOnly = Extract<Status, 'banned' | 'inactive'>;
// 'banned' | 'inactive'

NonNullable<T> — исключает null и undefined из типа:

type MaybeString = string | null | undefined;
type DefinitelyString = NonNullable<MaybeString>; // string

ReturnType<T> и Parameters<T> — извлекают типы из функций:

function getUser(id: number): User { /* ... */ }

type GetUserReturn = ReturnType<typeof getUser>; // User
type GetUserParams = Parameters<typeof getUser>; // [id: number]

Практическое применение

Utility types особенно полезны при работе с API и формами:

// Тип для создания пользователя — без id (его генерирует сервер)
type CreateUserDto = Omit<User, 'id'>;

// Тип для обновления — все поля опциональны
type UpdateUserDto = Partial<Omit<User, 'id'>>;

Как они устроены внутри

Bольшинство utility types реализованы через mapped types и conditional types:

// Упрощённая реализация Partial
type MyPartial<T> = {
  [K in keyof T]?: T[K];
};

// Упрощённая реализация Readonly
type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
};

Понимание внутреннего устройства позволяет создавать собственные utility types под специфические нужды проекта.

Что хочет услышать интервьюер

Кандидат перечисляет хотя бы 5–7 встроенных utility types (Partial, Required, Readonly, Pick, Omit, Record, Exclude, Extract)

Умеет объяснить разницу между Pick/Omit и Exclude/Extract (первые работают с объектами, вторые — с union-типами)

Приводит реальные примеры использования в контексте DTO, форм или API-запросов

Понимает, что utility types реализованы через mapped types и conditional types

Знает ReturnType и Parameters для работы с типами функций

Пример: Основные utility types

interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

// Partial — все поля опциональны
type UpdateUserDto = Partial<User>;

// Pick — только нужные поля
type UserPreview = Pick<User, 'id' | 'name'>;

// Omit — исключить поля
type CreateUserDto = Omit<User, 'id'>;

// Record — словарь
type PermissionMap = Record<User['role'], string[]>;
const permissions: PermissionMap = {
  admin: ['read', 'write', 'delete'],
  user: ['read'],
};

// Readonly — запрет мутаций
const frozenUser: Readonly<User> = {
  id: 1, name: 'Иван', email: 'ivan@mail.ru', role: 'user'
};

Пример: Exclude, Extract, NonNullable

type Status = 'active' | 'inactive' | 'banned' | null;

// Убираем null и конкретные значения
type ActiveStatus = Exclude<NonNullable<Status>, 'banned'>;
// 'active' | 'inactive'

// Оставляем только нужные значения
type NegativeStatus = Extract<Status, 'inactive' | 'banned'>;
// 'inactive' | 'banned'

Пример: ReturnType и Parameters

async function fetchUser(id: number, withRoles: boolean): Promise<User> {
  // имитация запроса к API
  return { id, name: 'Иван', email: 'ivan@mail.ru', role: 'user' };
}

// Извлекаем тип возвращаемого значения
type FetchUserResult = Awaited<ReturnType<typeof fetchUser>>; // User

// Извлекаем типы параметров
type FetchUserParams = Parameters<typeof fetchUser>; // [id: number, withRoles: boolean]

Пример: Собственный utility type

// Делаем только указанные поля обязательными, остальные — опциональными
type RequireFields<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;

type UserWithRequiredEmail = RequireFields<Partial<User>, 'email'>;
// email — обязателен, остальные поля — опциональны

Типичные ошибки

Путают Pick/Omit (для объектных типов) с Exclude/Extract (для union-типов)

Не знают утилиты для работы с функциями: ReturnType, Parameters, ConstructorParameters

Используют Partial везде, где нужен Omit — например, для DTO без id

Не умеют комбинировать utility types (например, Partial<Omit<T, 'id'>>)

Не понимают, как utility types устроены внутри — не могут написать аналог самостоятельно

Лучшие курсы по теме

изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Feature-Sliced Design

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.5
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее