Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

55 - Union to Intersection #122

Open
githubxiaowen opened this issue Sep 4, 2020 · 8 comments
Open

55 - Union to Intersection #122

githubxiaowen opened this issue Sep 4, 2020 · 8 comments
Labels
55 answer Share answers/solutions to a question en in English

Comments

@githubxiaowen
Copy link

type UnionToIntersection<U> = (U extends any ? (arg: U) => any : never) extends ((arg: infer I) => void) ? I : never

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#type-inference-in-conditional-types

@githubxiaowen githubxiaowen added answer Share answers/solutions to a question en in English labels Sep 4, 2020
@github-actions github-actions bot added the 55 label Sep 4, 2020
@Sociosarbis
Copy link

type UnionToIntersection<U> = (U extends any ? (arg: U) => any : never) extends ((arg: infer I) => void) ? I : never
type I = UnionToIntersection<'foo' | 42 | true> // never

type A = 'foo' | 42 | true

type B = A extends any ? (arg: A) => any : never // (arg: A) => any 

type C = B extends ((arg: infer I) => void) ? I : never //  'foo' | 42 | true

type D = 'foo' & 2 & true // never

Hi, @githubxiaowen ,I try your solution in my editor.It works when all statements combined as a type template.But When I separate those statements into three statements in order to figure out what mechanism your solution is based on, it didn't work as expect.

Could you give me more hints to understand the underlying magic of the solution. (I have read the link you attached above.)

BTW, do you know the reason why the three separated statement doesn't work the same as the template type ?

@jo32
Copy link

jo32 commented Nov 10, 2020

type UnionToIntersection<U> = (U extends any ? (arg: U) => any : never) extends ((arg: infer I) => void) ? I : never
type I = UnionToIntersection<'foo' | 42 | true> // never

type A = 'foo' | 42 | true

type B = A extends any ? (arg: A) => any : never // (arg: A) => any 

type C = B extends ((arg: infer I) => void) ? I : never //  'foo' | 42 | true

type D = 'foo' & 2 & true // never

Hi, @githubxiaowen ,I try your solution in my editor.It works when all statements combined as a type template.But When I separate those statements into three statements in order to figure out what mechanism your solution is based on, it didn't work as expect.

Could you give me more hints to understand the underlying magic of the solution. (I have read the link you attached above.)

BTW, do you know the reason why the three separated statement doesn't work the same as the template type ?

@Sociosarbis It is because 'foo' & 42 & true is logically never -- you can never find a type which is 42 and true at the same time.

the magic of this solution is given a type like (arg: U) => any | (arg: V) => any, if you want to find an argument(using keyword infer) satisfying U and V, the type of it must be U & V;

@swnb
Copy link

swnb commented Nov 24, 2020

amazing!

@vogler
Copy link

vogler commented Mar 4, 2021

If the intersection for a field is never, you can't provide a value for the object anymore.
So when using UnionToIntersection on objects out of your control the below StripNever may be useful.

type t = UnionToIntersection<{a: number, b: number} | {a: number, b: string}>;
const t1: t = {a: 1}; //  Property 'b' is missing in type '{ a: number; }' but required in type '{ a: number; b: number; }'
const t2: t = {a: 1, b: 1}; // Type 'number' is not assignable to type 'never'.

type NonNeverKeys<T> = { [K in keyof T]: T[K] extends never ? never : K }[keyof T];
type StripNever<T> = T extends object ? { [K in NonNeverKeys<T>]: StripNever<T[K]> } : T;

const t3: StripNever<t> = {a: 1}; // ok

@Jackie1210
Copy link

image

@wine-fall
Copy link

wine-fall commented Jan 18, 2022

The solution is amazing, however, i think write as below may be understood more easily

type UnionToIntersection<U, T = U> =  (U extends T ? (arg: U) => any : never) extends (arg: infer I) => void ? I : never;

And what does the U extends U mean? (when U is an Union Type) you can check link: #614

@kstratis
Copy link

kstratis commented Oct 9, 2022

type UnionToIntersection<U> = (U extends any ? (arg: U) => any : never) extends ((arg: infer I) => void) ? I : never
type I = UnionToIntersection<'foo' | 42 | true> // never

type A = 'foo' | 42 | true

type B = A extends any ? (arg: A) => any : never // (arg: A) => any 

type C = B extends ((arg: infer I) => void) ? I : never //  'foo' | 42 | true

type D = 'foo' & 2 & true // never

Hi, @githubxiaowen ,I try your solution in my editor.It works when all statements combined as a type template.But When I separate those statements into three statements in order to figure out what mechanism your solution is based on, it didn't work as expect.

Could you give me more hints to understand the underlying magic of the solution. (I have read the link you attached above.)

BTW, do you know the reason why the three separated statement doesn't work the same as the template type ?

I was wondering the exact same thing, so I turned to SO.
Turns out your break-down is missing generics:
https://stackoverflow.com/a/74003461/178728

@Sociosarbis
Copy link

type UnionToIntersection<U> = (U extends any ? (arg: U) => any : never) extends ((arg: infer I) => void) ? I : never
type I = UnionToIntersection<'foo' | 42 | true> // never

type A = 'foo' | 42 | true

type B = A extends any ? (arg: A) => any : never // (arg: A) => any 

type C = B extends ((arg: infer I) => void) ? I : never //  'foo' | 42 | true

type D = 'foo' & 2 & true // never

Hi, @githubxiaowen ,I try your solution in my editor.It works when all statements combined as a type template.But When I separate those statements into three statements in order to figure out what mechanism your solution is based on, it didn't work as expect.
Could you give me more hints to understand the underlying magic of the solution. (I have read the link you attached above.)
BTW, do you know the reason why the three separated statement doesn't work the same as the template type ?

I was wondering the exact same thing, so I turned to SO. Turns out your break-down is missing generics: https://stackoverflow.com/a/74003461/178728

an answer with clear explanations. thx @kstratis

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
55 answer Share answers/solutions to a question en in English
Projects
None yet
Development

No branches or pull requests

8 participants