How can I make a type which will make a one object type from unions of objects, which will contain properties of all objects of union type, but values will intersections?
Example: I need to make from type { foo: 1 } | { foo: 2; bar: 3 } | { foo: 7; bar: 8 } a type {foo: 1 | 2 | 7; bar: 3 | 8}.
Important note: I want to make one object type instead of an intersection like {foo: 1 | 2} & {bar: 3}
I have written a type, ComplexUnionToIntersection, which should do it, but it's ignoring properties which do not exist in all objects of the union (bar in my examples).
My code:
/**
* 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: result of test case must be `{foo: 1 | 2; bar: 3}`
type testCase1 = ComplexUnionToIntersection<{ foo: 1 } | { foo: 2; bar: 3 }>; // actually return `{ foo: 1 | 2; }`
// TODO: result of test case must be `{foo: 1 | 2 | 7; bar: 3 | 8}`
type testCase2 = ComplexUnionToIntersection<
{ foo: 1 } | { foo: 2; bar: 3 } | { foo: 7; bar: 8 }
>;
// TODO: result of test case must be `{foo: 1 | 2; bar: 3 | 8}`
type testCase3 = ComplexUnionToIntersection<
{ foo: 1 } | { foo: 2; bar: 3 } | { bar: 8 }
>;
// TODO: result of test case must be `{foo?: 1 | 2; bar: 3 | 8}`
type testCase4 = ComplexUnionToIntersection<
{ foo: 1 } | { foo?: 2; bar: 3 } | { bar: 8 }
>;