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:
type UnionToIntersection<U> =
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
That 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<FunctionUnion>
// 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
, so
type Weird = UnionToIntersection<string | number | boolean>
becomes
type Weird = string & number & true & false
which in TS3.6+ gets eagerly reduced to
type Weird = never
because it's impossible to have a value which is string
and number
and true
and false
.
Hope that helps. Good luck!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…