patterntypescriptCritical
Transform union type to intersection type
Viewed 0 times
intersectiontypetransformunion
Problem
Is there a way to transform a union type into an intersection type :
I would like to apply a transformation to
type FunctionUnion = (() => void) | ((p: string) => void)
type FunctionIntersection = (() => void) & ((p: string) => void)I would like to apply a transformation to
FunctionUnion to get FunctionIntersectionSolution
You want union to intersection? Distributive conditional types and inference from conditional types can do that. (Don't think it's possible to do intersection-to-union though, sorry) Here's the evil magic:
That distributes the union
Likewise, multiple candidates for the same type variable in contra-variant positions causes an intersection type to be inferred.
Let's see if it works.
First let me parenthesize your
Testing:
Looks good!
Be careful that in general
becomes
which in TS3.6+ gets eagerly reduced to
because it's impossible to have a value which is
type UnionToIntersection =
(U extends any ? (x: U)=>void : never) extends ((x: infer I)=>void) ? I : neverThat distributes the union
U and repackages it into a new union where all the consitutents are in contravariant position. That allows the type to be inferred as an intersection I, as mentioned in the handbook:Likewise, multiple candidates for the same type variable in contra-variant positions causes an intersection type to be inferred.
Let's see if it works.
First let me parenthesize your
FunctionUnion and FunctionIntersection because TypeScript seems to bind the union/intersection more tightly than function return:type FunctionUnion = (() => void) | ((p: string) => void);
type FunctionIntersection = (() => void) & ((p: string) => void);Testing:
type SynthesizedFunctionIntersection = UnionToIntersection
// inspects as
// type SynthesizedFunctionIntersection = (() => void) & ((p: string) => void)Looks good!
Be careful that in general
UnionToIntersection<> exposes some details of what TypeScript thinks is an actual union. For example, boolean is apparently internally represented as true | false, sotype Weird = UnionToIntersectionbecomes
type Weird = string & number & true & falsewhich in TS3.6+ gets eagerly reduced to
type Weird = neverbecause it's impossible to have a value which is
string and number and true and false.Code Snippets
type UnionToIntersection<U> =
(U extends any ? (x: U)=>void : never) extends ((x: infer I)=>void) ? I : nevertype FunctionUnion = (() => void) | ((p: string) => void);
type FunctionIntersection = (() => void) & ((p: string) => void);type SynthesizedFunctionIntersection = UnionToIntersection<FunctionUnion>
// inspects as
// type SynthesizedFunctionIntersection = (() => void) & ((p: string) => void)type Weird = UnionToIntersection<string | number | boolean>type Weird = string & number & true & falseContext
Stack Overflow Q#50374908, score: 481
Revisions (0)
No revisions yet.