← Назад к вопросам

Когда используются union types в TypeScript?

1.0 Junior🔥 181 комментариев
#TypeScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI20 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Когда используются union types в TypeScript?

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

Основное определение

Union type — это способ сказать TypeScript: "эта переменная может быть ИЛИ одного типа, ИЛИ другого, ИЛИ третьего".

// Переменная может быть строкой или числом
let id: string | number;
id = 42;         // ✅ OK
id = 'user-123'; // ✅ OK
id = true;       // ❌ Ошибка: тип boolean не совместим

Когда использовать Union Types

1. Функции с гибкими параметрами

function parseValue(value: string | number): string {
  if (typeof value === 'string') {
    return value.toUpperCase();
  } else {
    return value.toString();
  }
}

parseValue('hello');  // ✅
parseValue(42);       // ✅
parseValue(true);     // ❌ Ошибка

2. Возвращаемые значения с ошибками

function fetchUser(id: number): { user: User } | { error: string } {
  if (!id) {
    return { error: 'Invalid ID' };
  }
  return { user: { id, name: 'John' } };
}

const result = fetchUser(1);
if ('error' in result) {
  console.log('Error:', result.error);
} else {
  console.log('User:', result.user);
}

3. Логические состояния в приложении

type LoadingState = 'idle' | 'loading' | 'success' | 'error';

interface DataState {
  status: LoadingState;
  data?: unknown;
  error?: string;
}

const state: DataState = {
  status: 'loading',
  data: null
};

4. Props компонентов React

interface ButtonProps {
  size: 'small' | 'medium' | 'large';
  variant: 'primary' | 'secondary' | 'danger';
  onClick?: () => void;
}

export const Button: React.FC<ButtonProps> = ({
  size,
  variant,
  onClick
}) => {
  return <button className={`btn-${size} btn-${variant}`}>{/* */}</button>;
};

5. Обработка данных разных структур

type ApiResponse = 
  | { type: 'success'; data: User[] }
  | { type: 'error'; code: number; message: string }
  | { type: 'loading' };

function handleResponse(response: ApiResponse) {
  switch (response.type) {
    case 'success':
      console.log('Users:', response.data);
      break;
    case 'error':
      console.log(`Error ${response.code}: ${response.message}`);
      break;
    case 'loading':
      console.log('Loading...');
  }
}

Type Guards для работы с Union Types

function processInput(value: string | number | boolean) {
  // Проверка типа typeof
  if (typeof value === 'string') {
    console.log('String length:', value.length);
  } else if (typeof value === 'number') {
    console.log('Number value:', value.toFixed(2));
  } else {
    console.log('Boolean value:', value);
  }
}

// Проверка instanceof
function handleEvent(event: MouseEvent | KeyboardEvent) {
  if (event instanceof MouseEvent) {
    console.log('Mouse coords:', event.clientX, event.clientY);
  } else {
    console.log('Key pressed:', event.key);
  }
}

// Проверка in (для объектов)
interface Admin { role: 'admin'; permissions: string[] }
interface User { role: 'user'; name: string }

function printRole(user: Admin | User) {
  if ('permissions' in user) {
    console.log('Admin with permissions:', user.permissions);
  } else {
    console.log('User:', user.name);
  }
}

Discriminated Union (рекомендуемый подход)

Для сложных Union типов используйте discriminated union с общим полем:

type Result<T> = 
  | { status: 'success'; value: T }
  | { status: 'error'; error: Error }
  | { status: 'pending' };

function handleResult<T>(result: Result<T>) {
  switch (result.status) {
    case 'success':
      console.log('Success:', result.value);
      break;
    case 'error':
      console.log('Error:', result.error.message);
      break;
    case 'pending':
      console.log('Loading...');
  }
}

Union Types vs Any

// ❌ Плохо - используется any
function process(value: any) {
  return value.toUpperCase(); // может упасть
}

// ✅ Хорошо - явно указаны типы
function process(value: string | { toString(): string }) {
  return typeof value === 'string' 
    ? value.toUpperCase() 
    : value.toString().toUpperCase();
}

Практические советы

  1. Предпочитайте Union Types любому значению вместо any
  2. Используйте discriminated union для сложных сценариев
  3. Добавляйте type guards для типобезопасности
  4. Документируйте возможные типы в комментариях
  5. Используйте narrowing (сужение типов) для безопасности

Union Types — это мощный инструмент TypeScript, который делает код безопаснее и понятнее, предотвращая ошибки на этапе разработки.