4

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.

calvinyoung
  • 346
  • 2
  • 12
  • That's not a [discriminated union](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions) (a union where each member can be distinguished from the others by a common property with different literal values), it's just a union. What you are asking for is (essentially) turning the union into an intersection, which is a duplicate of [this question](https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type). – jcalz Aug 23 '20 at 01:17
  • Note that if you actually did merge a discriminated union (e.g., `{type: "circle", radius: number} | {type: "square", length: number}`) this way, you'd end up with an impossible type for the discriminant (e.g., `{type: never, radius: number, length: number}`) – jcalz Aug 23 '20 at 01:24

1 Answers1

12

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. Hope that helps; good luck!

Playground link to code

jcalz
  • 264,269
  • 27
  • 359
  • 360