How can I create a unified object type from multiple object unions, containing all properties but with intersecting values?
For example, I want to transform the type
{ foo: 1 } | { foo: 2; bar: 3 } | { foo: 7; bar: 8 }
into the type {foo: 1 | 2 | 7; bar: 3 | 8}
.
Note: Instead of creating an intersection like {foo: 1 | 2} & {bar: 3}
, I aim to generate a single object type.
I've developed a type called ComplexUnionToIntersection
to achieve this. However, it currently disregards properties that don't exist in all objects within the union (such as `bar` in my examples).
Here is the code snippet:
/**
* More info: https://fettblog.eu/typescript-union-to-intersection/
*/
export type UnionToIntersection<U> = (
U extends any ? (k: U) => void : never
) extends (k: infer I) => void
? I
: never;
/**
* Target type
*/
export type ComplexUnionToIntersection<U> = { o: U } extends { o: infer X }
? {
[K in keyof (X & U)]: (X & U)[K];
}
: UnionToIntersection<U>;
Test cases:
// TODO: test case should result in `{foo: 1 | 2; bar: 3}`
type testCase1 = ComplexUnionToIntersection<{ foo: 1 } | { foo: 2; bar: 3 }>; // currently returns `{ foo: 1 | 2; }`
// TODO: test case should result in `{foo: 1 | 2 | 7; bar: 3 | 8}`
type testCase2 = ComplexUnionToIntersection<
{ foo: 1 } | { foo: 2; bar: 3 } | { foo: 7; bar: 8 }
>;
// TODO: test case should result in `{foo: 1 | 2; bar: 3 | 8}`
type testCase3 = ComplexUnionToIntersection<
{ foo: 1 } | { foo: 2; bar: 3 } | { bar: 8 }
>;
// TODO: test case should result in `{foo?: 1 | 2; bar: 3 | 8}`
type testCase4 = ComplexUnionToIntersection<
{ foo: 1 } | { foo?: 2; bar: 3 } | { bar: 8 }
>;
Access TS Playground here