Union и Intersection типы

Union типы в TypeScript позволяют объединить несколько типов в один. Это означает, что переменная или параметр могут иметь значение одного из нескольких типов. Чтобы создать union тип, используется оператор |, который позволяет комбинировать типы.

Пример использования union типов:

let value: string | number;

value = "Hello";  // допустимо
value = 42;       // допустимо
value = true;     // ошибка: тип 'boolean' не совместим с типом 'string | number'

В этом примере переменная value может быть либо строкой, либо числом. Однако она не может быть, например, булевым значением, так как это не входит в определённый union тип.

Union типы особенно полезны при работе с переменными, которые могут принимать различные значения в зависимости от контекста. Например, это может быть актуально при описании ответов от API, где поле может быть строкой или числом, в зависимости от ситуации.

function formatValue(value: string | number): string {
  if (typeof value === "string") {
    return value.toUpperCase();
  } else {
    return value.toFixed(2);
  }
}

console.log(formatValue("hello")); // "HELLO"
console.log(formatValue(123.456)); // "123.46"

В этом примере функция formatValue принимает либо строку, либо число, и возвращает результат в виде строки. Тип переменной value проверяется с помощью typeof, что позволяет различать строки и числа и применять соответствующее форматирование.

Intersection типы в TypeScript

Intersection типы позволяют комбинировать несколько типов в один, создавая тип, который имеет все свойства каждого из исходных типов. Для создания intersection типов используется оператор &.

Пример использования intersection типов:

type Person = {
  name: string;
  age: number;
};

type Employee = {
  employeeId: string;
  department: string;
};

type EmployeeDetails = Person & Employee;

const employee: EmployeeDetails = {
  name: "Alice",
  age: 30,
  employeeId: "E12345",
  department: "HR"
};

В данном примере создаётся новый тип EmployeeDetails, который является комбинацией типов Person и Employee. Это значит, что объект employee должен иметь все свойства, которые определены в этих двух типах.

Intersection типы полезны при создании сложных объектов, которые должны включать в себя свойства из разных типов. Например, тип EmployeeDetails содержит свойства и от Person, и от Employee, что делает его подходящим для описания сотрудников, которые являются одновременно людьми и работниками.

Сравнение Union и Intersection типов

Union и Intersection типы оба объединяют несколько типов, но делают это по-разному:

  • Union типы позволяют переменной или параметру быть одним из нескольких типов. То есть значение может быть одним из нескольких вариантов, но не несколькими сразу.

    Пример:

    let value: string | number;

    Переменная value может быть либо строкой, либо числом, но не обоими типами одновременно.

  • Intersection типы требуют, чтобы объект или переменная имели все свойства, определённые для каждого из типов. То есть значение должно одновременно удовлетворять всем требованиям каждого из типов.

    Пример:

    type EmployeeDetails = Person & Employee;

    В этом случае объект должен быть одновременно и Person, и Employee, иметь все их свойства.

Использование Union и Intersection типов в реальных задачах

Union типы часто используются в ситуациях, когда тип данных может быть различным в зависимости от контекста. Например, это может быть полезно при работе с API, где возвращаемые данные могут иметь разные форматы, или при обработке пользовательского ввода, который может быть как строкой, так и числом.

Intersection типы полезны в случаях, когда необходимо объединить несколько типов в один, чтобы объект мог удовлетворять сразу нескольким интерфейсам или типам. Например, это может быть полезно при проектировании сложных объектов, которые должны включать в себя характеристики из разных областей (например, объект, который является и сотрудником, и пользователем системы).

Динамические Union и Intersection типы

TypeScript позволяет создавать более сложные структуры типов, комбинируя их динамически. Например, можно использовать условные типы, чтобы выбирать между union и intersection в зависимости от определённых условий.

Пример с условными типами:

type IsString<T> = T extends string ? "Yes" : "No";

type Test1 = IsString<string>;  // "Yes"
type Test2 = IsString<number>;  // "No"

В этом примере тип IsString возвращает строку "Yes", если переданный тип — это строка, и "No", если это не строка. Этот подход можно использовать вместе с union и intersection типами, чтобы динамически определять, какие типы могут быть объединены или пересечены.

Заключение

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