Exclude<T, U> — это utility type, появившийся в TypeScript для вычитания одного типа из другого, когда требуется исключить некоторые значения из union-типа.
Изначально в TypeScript не было удобного способа вычесть тип из другого. При создании обобщённых API, а также при рефакторинге часто требовалось получать "остаточный" тип — всё, кроме запрещённых значений. Вместо ручных манипуляций c union приходилось поддерживать несколько похожих интерфейсов.
Например, когда есть тип 'A | B | C', но нужно получить тип без B. Это часто требуется при построении сложных входных параметров функций, фильтрации разрешённых значений и динамическом формировании типов.
Exclude решает данную проблему. Его упрощённая сигнатура такова:
type Exclude<T, U> = T extends U ? never : T;
Он возвращает тип, исключающий из T все члены U.
Пример:
type Status = 'draft' | 'published' | 'removed'; type UserVisibleStatus = Exclude<Status, 'removed'>; const visible: UserVisibleStatus = 'draft'; // OK
Ключевые особенности:
Можно ли использовать Exclude для обычных типов, а не union?
Если T не является union-типа, но входит в U — Exclude все равно сработает, но результатом может быть never или T, что не всегда интуитивно.
Exclude<'a', 'a'> // результат: never Exclude<'a', 'b'> // результат: 'a'
Удаляет ли Exclude все упоминания типа в структуре объекта?
Нет, Exclude не проходит рекурсивно по вложенным полям типа, исключает только на верхнем уровне union.
Как работает Exclude с интерфейсами и типами-объектами?
Он сравнивает весь тип, а не отдельные свойства. Поэтому Exclude из union нескольких интерфейсов — удаляет только те, которые полностью совпадают с U.
interface A { x: number }; interface B { y: string }; // Exclude<A|B, B> даёт: A (B полностью совпадает)
Валидация ролей пользователя через Exclude<UserRoles, 'admin'>, но забыли, что Exclude не применяется к вложенным структурам — права 'admin:sub' не были исключены.
Плюсы:
Минусы:
Использование Exclude для ограничения public API действиями: Exclude<Action, 'delete'>, что исключает опасную операцию.
Плюсы:
Минусы: