Transform union type to intersection type

后端 未结 2 1818
感动是毒
感动是毒 2020-11-21 14:55

Is there a way to transform a union type into an intersection type :

type FunctionUnion = () => void | (p: string) => void
type FunctionIntersection =          


        
2条回答
  •  清歌不尽
    2020-11-21 15:16

    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 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
    // 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
    

    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!

提交回复
热议问题