Search code examples
typescripttypescript-genericstypescript-conditional-types

Typescript distributive over mapped generics?


I know Typescript distributes generic types in conditionals, but why does it distribute when there is no condition?

type Box<U> = { [K in keyof U]: [U[K]] }; // a random mapping
type Objects = {a: 1, b: 2} | {a: 3, c: 4};

type Distributed = Box<Objects>;
type NotDistributed = { [K in keyof Objects]: [Objects[K]] }; // same mapping as Box<U>, but different result

Notice the difference between the 2 generated types:

type Distributed = {
    a: [1];
    b: [2];
} | {
    a: [3];
    c: [4];
}

type NotDistributed = {
    a: [1 | 3];
}

I searched but didn't find any explanation for this difference.


Solution

  • Yes, homomorphic mapped types (see What does "homomorphic mapped type" mean?) operating on generic type parameters will distribute over unions in their type arguments, whereas mapped types on specific types will not. This behavior was implemented in microsoft/TypeScript#12447 (where it was called "isomorphic" as opposed to "homomorphic"). It is intentional behavior, as described in microsoft/TypeScript#44850.

    So Box<Objects> distributes over the union in Objects, while {[K in keyof Objects]: ⋯} does not.