calvinyoung
calvinyoung

Reputation: 386

Merge discriminated union of object types in Typescript

Is it possible to merge all properties in a discriminated union of object types?

As an example, suppose I have the following type:

type UnionType = { name: string; } | { age: number; } | { visible: boolean; }

Is it possible to then merge these into a single type like this:

// Expect: { name: string; age: number; visible: boolean };
type Props = MagicType<UnionType>;

This is essentially the inverse of the Unionize type from utility-types.

Upvotes: 6

Views: 2638

Answers (1)

jcalz
jcalz

Reputation: 327934

You can turn a union into an intersection using the answer to this question, with all the caveats that come with it:

type UnionToIntersection<U> =
  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

If you don't like the way { name: string; } & { age: number; } & { visible: boolean; } looks, you can ask the compiler to reinterpret it as a single object type by using an identity mapping:

type MagicType<U> = 
  UnionToIntersection<U> extends infer O ? { [K in keyof O]: O[K] } : never;

This gives you the following output:

type Props = MagicType<UnionType>;
/* type Props = {
    name: string;
    age: number;
    visible: boolean;
} */

which is what you want.

Playground link to code

Upvotes: 15

Related Questions