TS Utility Types

Utility Types — встроенные в TypeScript generic-типы, которые преобразуют существующие типы: делают поля опциональными, только для чтения, выбирают подмножество свойств или исключают их.

Зачем нужно

  • Позволяют переиспользовать один базовый тип в разных формах без дублирования кода
  • Заменяют ручное написание производных интерфейсов: Partial<User> вместо { id?: number; name?: string; ... }
  • Типы DTO, формы, патч-запросы, конфиги — всё это производные от одного источника истины

Где используется

  • Partial<T> — формы редактирования, PATCH-запросы
  • Required<T> — проверка что все поля заполнены перед отправкой
  • Readonly<T> — иммутабельные конфиги, props в React
  • Pick<T, K> и Omit<T, K> — DTO, публичные API-контракты
  • Record<K, V> — словари, маппинги, индексные объекты
  • ReturnType<F>, Parameters<F> — вывод типов из существующих функций
  • Awaited<T> — тип результата промиса

Основной контент

Partial и Required

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

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

function updateUser(id: number, patch: Partial<User>): void {
  // PATCH /api/users/:id
}
updateUser(1, { name: "Alice" }); // OK — частичное обновление

// Все поля обязательны
type FullUser = Required<User>;
// { id: number; name: string; email: string; age: number }

Readonly

type Config = Readonly<{
  apiUrl: string;
  timeout: number;
}>;

const config: Config = { apiUrl: "https://api.example.com", timeout: 5000 };
config.apiUrl = "other"; // Ошибка! Cannot assign to 'apiUrl' — read-only

// React props — обычно Readonly
type ButtonProps = Readonly<{
  label: string;
  onClick:  => void;
}>;

Pick и Omit

interface Article {
  id: number;
  title: string;
  body: string;
  authorId: number;
  createdAt: Date;
  updatedAt: Date;
}

// Только нужные поля для превью
type ArticlePreview = Pick<Article, "id" | "title" | "createdAt">;
// { id: number; title: string; createdAt: Date }

// Убрать служебные поля для формы создания
type CreateArticleDto = Omit<Article, "id" | "createdAt" | "updatedAt">;
// { title: string; body: string; authorId: number }

Record

type Status = "active" | "inactive" | "banned";
type StatusLabel = Record<Status, string>;

const labels: StatusLabel = {
  active: "Активен",
  inactive: "Неактивен",
  banned: "Заблокирован",
  // пропустить ключ — ошибка компилятора
};

// Словарь пользователей по id
type UserMap = Record<number, User>;
const users: UserMap = { 1: { id: 1, name: "Alice", email: "a@b.com", age: 25 } };

Exclude и Extract

type EventType = "click" | "hover" | "focus" | "blur";

// Убрать варианты из union
type MouseEvents = Exclude<EventType, "focus" | "blur">;
// "click" | "hover"

// Оставить только совпадающие
type FocusEvents = Extract<EventType, "focus" | "blur">;
// "focus" | "blur"

ReturnType, Parameters, Awaited

function createUser(name: string, email: string): { id: number; name: string } {
  return { id: Math.random, name };
}

type CreatedUser = ReturnType<typeof createUser>;
// { id: number; name: string }

type CreateUserArgs = Parameters<typeof createUser>;
// [name: string, email: string]

// Awaited — тип разрешённого промиса
async function fetchData: Promise<{ items: string }> {
  return { items: ["a", "b"] };
}

type FetchResult = Awaited<ReturnType<typeof fetchData>>;
// { items: string }

NonNullable

type MaybeUser = User | null | undefined;
type DefiniteUser = NonNullable<MaybeUser>; // User

function processUser(user: MaybeUser): void {
  if (user == null) return;
  const u: NonNullable<typeof user> = user; // u: User
}

Частые ошибки

  • Путать Partial и опциональностьPartial<T> делает поля опциональными, но не убирает их из типа
  • Использовать Omit с несуществующими ключами — TypeScript не всегда даёт ошибку при неверном ключе в Omit
  • Record<string, T> вместо Record<LiteralUnion, T> — теряется проверка полноты ключей
  • Не использовать Awaited — написать ReturnType<typeof fn> вместо Awaited<ReturnType<typeof fn>> для async-функции

Связанные темы

Ресурсы