Во-первых, спасибо за ссылку для аналогичной проблемы, я взял оттуда тип утилиты - OptionalPropertyOf
. Ниже решение вашей проблемы
type OptionalPropertyOf<T> = Exclude<{
[K in keyof T]: T extends Record<K, T[K]>
? never
: K
}[keyof T], undefined>
type Merge<T1, T2,
First = {
[K in (keyof T1)]: K extends keyof T2 ? T1[K] | T2[K] : T1[K]
}, OptionalSecond = {
[K in Exclude<OptionalPropertyOf<T2>, keyof T1>]+?: T2[K]
},
NonOptionalSecond = {
[K in Exclude<keyof T2, keyof First | keyof OptionalSecond>]: T2[K]
}> = First & OptionalSecond & NonOptionalSecond
// Example
type A = {
a: string,
b?: number,
f: number,
}
type B = {
a: boolean,
b? : string,
c?: string,
e: number
}
type C = Merge<A, B>
/* type C evaluated as
{
a: string | boolean;
b?: string | number | undefined;
f: number;
c?: string | undefined;
e: number;
}
*/
const value: C = {
a: true,
e: 1,
f: 2
}
Мы сделали три шага:
- type
First
представляет все поля T1
+, если T2
имеет то же самое поле, которое мы объединяем с помощью объединения - тип
OptionalSecond
представляет поля, которые являются необязательными в T2
, но не использовались в типе First
. Мы говорим здесь +?
, чтобы эти поля оставались необязательными, здесь - type
NonOptionalSecond
представляет каждое поле в T2
, которое является дополнительным и необязательным
В результате мы имеем все необязательные поля обоих типов, также в случае дублирования объединение выполняется объединением.