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

Как ограничить выбор типа, который приходит в функцию?

2.0 Middle🔥 141 комментариев
#TypeScript

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

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

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

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

Когда функция принимает параметр, мы можем ограничить количество допустимых типов несколькими способами.

1. Union типы (|)

Позволяет указать несколько конкретных типов:

function processValue(value: string | number) {
  console.log(value);
}

processValue('hello'); // ✅ OK
processValue(42); // ✅ OK
processValue(true); // ❌ Error: Type 'boolean' is not assignable

2. Literal типы

Ограничивают значения конкретными строками или числами:

function setStatus(status: 'pending' | 'success' | 'error') {
  // status может быть ТОЛЬКО одно из трех значений
}

setStatus('pending'); // ✅ OK
setStatus('success'); // ✅ OK
setStatus('failed'); // ❌ Error

3. Enum типы

Для набора именованных констант:

enum Color {
  Red = 'RED',
  Green = 'GREEN',
  Blue = 'BLUE'
}

function setColor(color: Color) {
  console.log(color);
}

setColor(Color.Red); // ✅ OK
setColor('RED'); // ❌ Error (если строго типизировано)

4. Generic constraints (Generics с ограничениями)

Ограничивают тип с помощью extends:

// Функция принимает только объекты
function getKeys<T extends object>(obj: T): (keyof T)[] {
  return Object.keys(obj) as (keyof T)[];
}

getKeys({ name: 'John', age: 30 }); // ✅ OK
getKeys('string'); // ❌ Error: string is not assignable to object

5. Conditional типы

Создают типы на основе условия:

type IsString<T> = T extends string ? true : false;

type A = IsString<'hello'>; // true
type B = IsString<number>; // false

6. Overloading (Перегрузка функций)

Определяет несколько сигнатур функции:

function process(value: string): string;
function process(value: number): number;
function process(value: string | number): string | number {
  if (typeof value === 'string') {
    return value.toUpperCase();
  }
  return value * 2;
}

process('hello'); // ✅ returns string
process(42); // ✅ returns number

7. Type Guards (Проверка типов)

Динамическая проверка типа в runtime:

function process(value: string | number) {
  if (typeof value === 'string') {
    console.log(value.toUpperCase()); // value здесь string
  } else {
    console.log(value * 2); // value здесь number
  }
}

8. Keyof ограничения

Ограничивает значение только ключами объекта:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: 'John', age: 30 };
getProperty(user, 'name'); // ✅ OK
getProperty(user, 'email'); // ❌ Error: 'email' не существует

Практические примеры

API ответ с ограниченным статусом

interface ApiResponse {
  status: 'success' | 'error' | 'pending';
  data?: unknown;
  message?: string;
}

function handleResponse(response: ApiResponse) {
  switch (response.status) {
    case 'success':
      console.log('Успех!');
      break;
    case 'error':
      console.log('Ошибка!');
      break;
    case 'pending':
      console.log('Ожидание...');
      break;
  }
}

Функция с ограниченным типом параметра

function formatValue<T extends string | number | boolean>(value: T): string {
  return String(value);
}

formatValue('text'); // ✅ OK
formatValue(42); // ✅ OK
formatValue(true); // ✅ OK
formatValue({}); // ❌ Error

Ограничение по структуре

interface WithId {
  id: number;
}

function getId<T extends WithId>(obj: T): number {
  return obj.id;
}

getId({ id: 1, name: 'John' }); // ✅ OK
getId({ name: 'John' }); // ❌ Error: отсутствует id

Сравнение подходов

ПодходИспользованиеГибкость
Union typesНесколько конкретных типовСредняя
Literal typesКонкретные значенияНизкая
GenericsПереиспользуемые типыВысокая
OverloadingРазные типы → разные результатыСредняя
Type guardsRuntime проверкаВысокая

Ключевые моменты

  • Union типы для нескольких допустимых типов
  • Literal типы для конкретных значений
  • Generics с extends для гибких ограничений
  • Type guards для динамической проверки типов
  • Overloading для разных поведений по типам

Правильное ограничение типов делает код безопаснее и помогает поймать ошибки на этапе разработки, а не в runtime.