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

Что такое Condition Types?

2.0 Middle🔥 151 комментариев
#JavaScript Core

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

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

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

Что такое Condition Types (Условные типы) в TypeScript?

Condition Types — это мощный механизм TypeScript, который позволяет создавать типы, зависящие от других типов, на основе условий, подобно тому, как в JavaScript работает оператор if. Это одна из ключевых фигур условной типизации (conditional typing), которая значительно расширяет возможности системы типов, делая её более выразительной и адаптивной.

Основная концепция и синтаксис

Условные типы используют синтаксис, напоминающий тернарный оператор, но для типов:

T extends U ? X : Y

Здесь:

  • T — проверяемый тип.
  • U — тип, с которым происходит сравнение (условие).
  • extends — ключевое слово, проверяющее, является T подтипом U или ему эквивалентным.
  • X — тип, который выбирается, если условие истинно (true).
  • Y — тип, который выбирается, если условие ложно (false).

Как это работает на практике

Рассмотрим простой пример. Мы хотим создать тип, который определяет, является ли входной тип строкой, и в зависимости от этого выбирает другой тип:

type IsString<T> = T extends string ? 'Да, это строка' : 'Нет, это не строка';

type Result1 = IsString<'hello'>; // Результат: 'Да, это строка'
type Result2 = IsString<number>;  // Результат: 'Нет, это не строка'

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

Ключевые применения и преимущества

1. Создание сложных дженериков и утилит типов:
Condition Types — основа многих utility-типов из стандартной библиотеки TypeScript (lib.d.ts). Например, Exclude<T, U> или Extract<T, U> построены на условной типизации.

// Пример реализации Extract (выбирает из T типы, которые соответствуют U)
type MyExtract<T, U> = T extends U ? T : never;

type Test = MyExtract<string | number | boolean, string | number>; // Результат: string | number

2. Фильтрация и трансформация типов в объединениях (union types):
Когда T является объединением типов (например, A | B | C), TypeScript применяет условный тип дистрибутивно (distributive conditional types) к каждому элементу объединения. Это крайне мощное поведение.

type ToArray<T> = T extends any ? T[] : never;

type Result = ToArray<string | number>; // Дистрибутивно вычисляется как: string[] | number[]
// А не как: (string | number)[]

3. Инференция типов с infer:
Условные типы часто сочетаются с ключевым словом infer, которое позволяет "вытаскивать" и захватывать части других типов внутри условия. Это основа для таких типов как ReturnType<T> или Parameters<T>.

// Пример: тип, который получает тип первого элемента массива
type FirstElement<T> = T extends [infer First, ...any[]] ? First : never;

type Test1 = FirstElement<[string, number, boolean]>; // string
type Test2 = FirstElement<number[]>; // never (не является конкретным массивом с первым элементом)

4. Реализация паттернов типа "Type Guards" на уровне системы типов:
Вы можете создавать типы, которые ведут себя как фильтры, направляя код по разным ветвям типизации в зависимости от входных параметров.

Пример сложного использования

Предположим, мы хотим создать функцию-обёртку, которая возвращает промис, но если входное значение уже является промисом, мы просто возвращаем его. Condition Types помогут нам правильно определить возвращаемый тип функции:

type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

async function processValue<T>(value: T): Promise<UnwrapPromise<T>> {
    if (value instanceof Promise) {
        return value; // TypeScript понимает, что тип здесь - Promise<U>
    }
    return Promise.resolve(value);
}

// Использование:
const result1 = processValue(42); // Promise<number>
const result2 = processValue(Promise.resolve('hello')); // Promise<string> (не Promise<Promise<string>>!)

Ограничения и особенности

  • Дистрибутивность может быть нежелательной в некоторых случаях. Чтобы её отключить, можно обернуть проверяемый тип в массив или другой структурный тип: [T] extends [U] ? X : Y.
  • Условные типы могут создавать сложные вычисления, которые иногда затрудняют работу компилятора (особенно с рекурсивными типами). Важно соблюдать баланс.
  • Они работают только на уровне типов и не влияют на исполняемый код JavaScript. Это инструмент исключительно для статического анализа.

Заключение

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

  • Выражать логику выбора на уровне типов.
  • Строить адаптивные дженерики, которые точно отражают поведение функций и классов.
  • Реализовывать сложные трансформации типов, необходимые в современных библиотеках и фреймворках (например, в React для типизации пропсов или в различных ORM).

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

Что такое Condition Types? | PrepBro