Presumably the library authors decided that UnionOf<A | B | C>
should produce the same result as UnionOf<A> | UnionOf<B> | UnionOf<C>
, and the definition of _UnionOf
did not do that. The O extends unknown ? ... : never
check, which deceptively looks like it does nothing, causes that to happen.
Expressions that look like they do nothing but actually distribute across unions, when T
is a generic type parameter:
T extends unknown ? ... : never
T extends any ? ... : never
T extends T ? ... : never
If T
is a type parameter, as in the generic function function foo<T>(/*...*/): void
or the generic interface interface Foo<T> {/*...*/}
, then a type of the form T extends XXX ? YYY : ZZZ
is a distributive conditional type.
It distributes the conditional check across unions in T
. When T
is specified with some specific type, the compiler splits that type up into its union members, evaluates the check for each such member, and then joins the results back into a new union. So if F<T>
distributes across unions, then F<A | B | C>
will be the same as F<A> | F<B> | F<C>
.
Not all type functions are distributive across unions. For example, the keyof
operator does not turn unions of inputs into unions of outputs:
type KeyofA = keyof {a: string}; // "a"
type KeyofB = keyof {b: number}; // "b"
type KeyofAorB = keyof ({ a: string } | { b: number }); // never
Similarly, _UnionOf
is not distributive across unions (related to the fact that it uses keyof
in its definition):
type Oops = _UnionOf<{ a: string } | { b: number }>
// never
If you have a type function which is not distributive in unions and you want it to be, you can wrap it in a distributive conditional type:
type DistribKeyof<T> = T extends unknown ? keyof T : never;
type UnionKeyofAorB = DistribKeyof<{ a: string } | { b: number }>; // "a" | "b"
And therefore UnionOf
is distributive across unions:
type Correct = UnionOf<{ a: string } | { b: number }>
// string | number
Playground link to code