typescript - 如何實現一個工具型別來把多個介面使用 Object.assign 邏輯合併成一個?
我需要一個工具類型,能夠將傳入聯合中的兩個或更多接口合併成一個,不將重複的屬性解析為 never,而是進行覆蓋。它應該像 Object.assign 一樣工作,但作用於類型/接口。假設我們有三個類型:
type A = {a: number};
type B = {a: boolean, b: boolean};
type C = {c: boolean};
我想要一些可以將它們合併成一個的工具:
type MergedType = MergeTypes<A|B|C>;
在結果中,我想要得到以下介面:
type MergedType = {
a: boolean, // overwriting, not `never` in case of using intersection (A & B & C)
b: boolean,
c: boolean
}
有沒有辦法達到這種行為?我只能為兩個帶有不同泛型參數的介面寫一個工具函數
type MergeTypes<S, T> = Omit<S, keyof T> & T;
type MergedType = MergeTypes<A, B>;
但我完全不知道如何在聯合上迭代,並參考前一個參數來達到陣列 reduce 的邏輯。提前感謝你!
答案#1
type Pure<T> = { [K in keyof T]: T[K] } & unknown
type Check<T, Eq extends ([T, V] extends [V, T] ? '=' : '!='), V> = T
type Assign<T, U> = Pure<Omit<T, keyof U> & U>
type AssignList<A extends any[]> =
| A extends [infer F] ? F
: A extends [...infer F, infer L] ? Assign<AssignList<F>, L>
: never
type checkAssignList = {
case1: Check<AssignList<[{ a: 1 }]>, '=', { a: 1 }>,
// ^?
case2: Check<AssignList<[{ a: 1 }, { a: 2 }]>, '=', { a: 2 }>,
// ^?
case3: Check<AssignList<[{ a: 1 }, { a: 2 }, { a: 3 }]>, '=', { a: 3 }>,
// ^?
case4: Check<AssignList<[{ a: 1 }, { b: 2 }, { a: 3 }]>, '=', { a: 3, b: 2 }>,
// ^?
}
const assign = Object.assign as <T extends {}, A extends readonly any[]>(target: T, ...sources: A) => AssignList<[T, ...A]>
const checkAssignList = {
case1: assign({ a: 1 }),
// ^?
case2: assign({ a: 1 }, { a: 2 }),
// ^?
case3: assign({ a: 1 }, { a: 2 }, { a: 3 }),
// ^?
case4: assign({ a: 1 }, { b: 2 }, { a: 3 }),
// ^?
}
console.log(checkAssignList)
