Объединения и пересечения типов

Объединения и пересечения — это мощные инструменты TypeScript для комбинирования типов. Они позволяют точно описывать данные, которые могут принимать несколько форм или объединять свойства из разных источников.


Объединение типов (|)

Объединение (union) означает, что значение может соответствовать одному из нескольких типов. Обозначается вертикальной чертой |.

type ID = string | number;

function printId(id: ID): void {
  console.log(`ID: ${id}`);
}

printId("user_123"); // строка — допустимо
printId(42);         // число — допустимо

Литеральные объединения

Часто объединения используются с литералами для ограничения допустимых значений:

type Status = "active" | "inactive" | "pending";

function updateStatus(status: Status): void {
  // ...
}

updateStatus("active");   // OK
updateStatus("deleted");   // Ошибка: не входит в union

Такие типы делают код самодокументируемым и предотвращают ошибки при передаче недопустимых значений.


Пересечение типов (&)

Пересечение (intersection) создаёт тип, который объединяет все свойства из нескольких типов. Значение должно соответствовать всем указанным типам одновременно.

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

interface Admin {
  role: string;
  permissions: string[];
}

type AdminUser = User & Admin;

const admin: AdminUser = {
  name: "Алексей",
  email: "alex@example.com",
  role: "editor",
  permissions: ["read", "write"]
};

Пересечение особенно полезно при композиции пропсов в React-компонентах или при расширении базовых типов без наследования.


Сравнение с наследованием интерфейсов

Интерфейсы можно расширять через extends, но это работает только с другими интерфейсами. Пересечение работает с любыми типами — interface, type, примитивами и даже объединениями.

type BaseProps = { className?: string };
type ButtonVariant = { variant: "primary" | "secondary" };

type ButtonProps = BaseProps & ButtonVariant;

Это гибче, чем interface, особенно когда исходные типы определены как type.


Ограничения и проверка типов

При работе с объединениями TypeScript требует убедиться, что операция допустима для всех возможных вариантов. Часто используется проверка типа через typeof или сравнение со строковыми литералами.

function processValue(value: string | number): void {
  if (typeof value === "string") {
    console.log(value.toUpperCase());
  } else {
    console.log(value.toFixed(2));
  }
}

Без такой проверки TypeScript не позволит вызывать методы, специфичные только для одного из типов в объединении.