Typescript: проверить, является ли тип объединением

Можно ли проверить, является ли данный тип объединением?

type IsUnion<T> = ???

Зачем мне это нужно: в моем коде у меня есть единственный случай, когда некоторый полученный тип может быть объединением. Я справляюсь с дистрибутивным условным типом. Тем не менее, для того, кто смотрит на этот код, может быть не очевидно, почему DCT используется в первую очередь. Итак, я хочу, чтобы это было явно так: IsUnion<T> extends true? T extends Foo... IsUnion<T> extends true? T extends Foo...

Я сделал несколько попыток с UnionToIntersection, но UnionToIntersection. Я также придумал это:

type IsUnion<T, U extends T = T> =
    T extends any ?
    (U extends T ? false : true)
    : never

Это дает false для не профсоюзов, но по какой-то причине это дает boolean для союзов... И я понятия не имею, почему. Я также пытался infer U из T, но безуспешно.

PS Мой вариант использования может показаться кому-то не идеальным/правильным/хорошим, но в любом случае возник вопрос в названии, и я задаюсь вопросом, возможно ли это (я чувствую, что это так, но мне самому трудно это понять).

Ответ 1

Так что, похоже, я сам придумал ответ!

Вот тип (спасибо Тициану Черниковой-Драгомиру за упрощение!):

type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true

type Foo = IsUnion<'abc' | 'def'> // true
type Bar = IsUnion<'abc'> // false

И снова пригодился UnionToIntersection из jcalz!

Принцип основан на том, что объединение A | B A | B не расширяет пересечение A & B

= (U extends any? (k: U) => void: never) extends ((k: infer I) => void)? I: never type IsUnion= [T] extends [UnionToIntersection]? false: true type Foo = IsUnion<'sdf' | 'zcx'> type Bar = IsUnion<'sdf'> rel="nofollow noreferrer">Детская площадка

UPD. Я был достаточно глуп, чтобы не развивать свой тип из вопроса в этот, который также отлично работает:

type IsUnion<T, U extends T = T> =
    (T extends any ?
    (U extends T ? false : true)
        : never) extends false ? false : true

Он распределяет объединение T на составляющие, а также T а затем проверяет, расширяет ли U который является объединением, составляющую T Если да, то это не объединение (но я до сих пор не знаю, почему это не работает без добавления extends false? false: true, т.е. почему предыдущая часть возвращает boolean для объединений).