Выбор ответа Senior Условные и mapped-типы обновлено

Omit на дискриминированном объединении

Вопрос

Почему после Omit пропало сужение?

type Ev = { kind: 'click'; x: number; ts: number } | { kind: 'key'; key: string; ts: number };
type NoTs = Omit<Ev, 'ts'>;

Попробуйте сами

Выберите вариант, и откроется разбор.

Показать ответ и разбор

Коротко

Правильный ответ: Omit не распределяется: keyof Ev даёт только общие ключи, и x, key теряются. Omit<T, K это Pick<T, Exclude<keyof T, K, а keyof объединения даёт только общие ключи (kind, ts).

Варианты ответа

  1. Omit не распределяется: keyof Ev даёт только общие ключи, и x, key теряютсяправильный ответ
  2. Omit работает только с интерфейсами, а у type-алиасов объединения ломается
  3. Сужение пропадает из-за ts: number, которое есть в обоих вариантах объединения
  4. Omit удаляет вместе с ts и поле kind, потому что оно литерального типа

Разбор

Omit<T, K> это Pick<T, Exclude<keyof T, K>>, а keyof объединения даёт только общие ключи (kind, ts). Поэтому x и key теряются, и union схлопывается. Решение: распределительная версия type DistOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never. С интерфейсами Omit работает так же, а kind никто не удалял.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.