typescriptunion-typesconditional-typestype-theory

What does it mean for a type to distribute over unions?


I'm reading an article :"Unionize and Objectify: A Trick for Applying Conditional Types to Objects"

In TypeScript our most powerful tool is conditional types. This is because they have two unique abilities:

  • They distribute over unions.
  • They enable you to use the infer keyword.

What does 'distribute over unions' mean in general and in this context?


Solution

  • The term distributive refers to how union types should be treated when subjected to type-level operations (such as keyof or mapped types).

    Let's use an example.

    type Fruit =
      | { species: 'banana', curvature: number }
      | { species: 'apple', color: string }
    

    Let's assume that, for some reason, you want to know all possible keys that can exist on a Fruit.

    Non-distributive

    Your intuition may tell you to do:

    type KeyOfFruit = keyof Fruit; // "species"
    

    However, this will give you only the properties that exist on every member of the union. In our example, species is the only common property shared by all Fruit.

    It's the same as applying keyof to the union of the two types.

    keyof ({ species: 'banana', curvature: number } | { species: 'apple', color: string })
    

    Distributive

    With distribution, the operation is not performed on just the common properties. Instead, it is done on every member of the union separately. The results are then added together.

    type DistributedKeyOf<T> =
      T extends any
        ? keyof T
        : never
    
    type KeyOfFruit = DistributedKeyOf<Fruit>; // "species" | "curvature" | "color"
    

    In this case, TypeScript applied keyof to each member of the union, and summed the results.

    keyof { species: 'banana', curvature: number } | keyof { species: 'apple', color: string }