While skimming through the TypeScript challenges, I came across a particularly interesting one: How to turn a union to an intersection.
Unable to figure it out myself, I turned to the solutions where I found a great approach here and an even greater explanation given here by @jcalz.
The only problem in my way was this question: effectively a user tried to break down the solution in multiple separate statements and, to my surprise, the result was not the same. Instead of foo & bar we were getting foo | bar. Putting the solution back together as a "one-liner" the result gets "restored": foo & bar.
// Type definition
type UnionToIntersection<U> = (U extends any ? (arg: U) => any : never) extends ((arg: infer I) => void)
? I
: never;
// As expected 👍 ('foo' & 'bar' is never)
type I = UnionToIntersection<'foo' | 'bar'>; // never
// Let's break-down `UnionToIntersection`
type A = 'foo' | 'bar';
type B = A extends any ? (arg: A) => any : never // (arg: A) => any;
// This should have been 'foo' & 'bar' (never) just like `type I` 🤯
type C = B extends ((arg: infer I) => void) ? I : never // 'foo' | 'bar'
What's going on here? Shouldn't type I and type C be the same?
effectively a user tried to break down the solution in multiple separate statements
The user made a mistake. In the original type, U is a generic type which gets distributed in the conditional.
In B, you use A which is not a generic type. No distribution takes place.
If we modify B to also have a generic type U (which we just default to be A), we will see the same result never.
type B<U = A> = U extends any ? (arg: U) => any : never
type C = B extends ((arg: infer I) => void) ? I : never
// ^? never
Playground
Distributive conditional types work for (naked) parameter types.
Replace your
type B = A extends any ? (arg: A) => any : never // (arg: A) => any;
with
type BT<T> = T extends any ? (arg: T) => any : never;
type B = BT<A>
to see the difference
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With