Распределённые типы (Distributive Types) — это особенность TypeScript, проявляющаяся при работе с условными типами (T extends U ? X : Y). Когда переменная-тип слева от extends является объединением (union), TypeScript распределяет условие по каждому элементу объединения.
Пример:
// "Test<A> | Test<B> | Test<C>" type Test<T> = T extends string ? () => string : () => number; type Result = Test<'A' | 'B' | 'C'>;
Здесь Result распределится как:
Когда применяют — для написания универсальных API, манипуляций над объединениями, например, для фильтрации или сопоставления с образцом.
Особенности:
[T], распределение не произойдёт. Это способ "отключить" распределённость.Вопрос: Будет ли тип T[] extends number[] ? true : false распределённым?
Правильный ответ: Нет, распределённость происходит только если слева переменная-тип без обёртки в массив или кортеж. Например, условный тип T extends number ? ... будет распределять, но T[] extends number[] ? ... — нет.
История
Проект: Библиотека валидации props для React-компонентов. Хотели реализовать тип, превращающий union-пропсы в строгий интерфейс, но из-за незнания распределения тип стал неожиданно сложным (смешались свойства членов union). Исправили, добавив обёртку
[T], чтобы распределение не происходило.
История
Проект: Разрабатывали помещение всех типов события в одну функцию-обработчик. В условном типе ожидалось, что функция будет принимать каждый тип события через распределение, но без явного его использования реализовали обработку некорректно, что привело к ошибочным типам аргументов (union вместо отдельного вызова для каждого типа).
История
Проект: При создании собственных утилит-типов (типа Exclude, Extract) забыли, что распределение не произойдёт для кортежей и массивов. В результате тип Exclude не работал для массивов (например, тип
Exclude<["a"|"b"], "b">не удалял "b").