Обе ваши версии более или менее эквивалентны - переключаются только ветви истина / ложь в условном типе.
Ограничение T extends {[K in keyof U]?: any}
немного проблематично c: при удалении a
в two
возникает ошибка Type '{ a: number; }' has no properties in common with type '{ b?: any; }
, что на самом деле должно быть успехом.
Также следует помнить, что результирующий тип merge
не содержит определения объединенного типа из обоих типов , Мы можем изменить объявление следующим образом:
type UniqueObject<T, U> =
T & { [K in keyof U]: K extends keyof T ? never : U[K] }
Теперь компилятор корректно выдает ошибку с дублирующим свойством a
:
var one = { a: 1 }
var two = { a: 2, b: 3 }
// v a becomes never here
type Merge = UniqueObject<typeof one, typeof two> // { a: never; b: number; }
const res: Merge = { ...one, ...two } // errors now, cannot assign number to never
В следующем я немного упростил тип и все упаковано в компактную вспомогательную функцию для управления типами + оператор распространения:
function mergeUnique<T extends object, U extends object & { [K in keyof U]: K extends keyof T ? never : U[K] }>(o1: T, o2: U) {
return { ...o1, ...o2 }
}
const res21 = mergeUnique({ a: 1 }, { b: 3 })
const res22 = mergeUnique({ a: 1 }, { a: 2, b: 3 }) // error
const res23 = mergeUnique({ a: 1, c: 5 }, { b: 3 })
const res24 = mergeUnique({ a: 1}, { a: undefined }) // error
Пример кода