typescript - 如何合併介面中的所有值
我正在嘗試合併一個介面的所有值,例如:
interface IA {
a: string;
}
interface IB {
b: string;
}
interface IC {
c: string;
}
//...
interface IMap {
"a": IA;
"b": IB;
"c": IC;
//...
"z": IZ;
}
有沒有辦法創建一種類型,如:
type IAll = IMap["a"] & IMap["b"] & IMap["c"] & ... & IMap["z"];
我正在嘗試同時使用這個:
type valueMerge<T> = T[keyof T];
type valueMerge2<T extends keyof IMap = keyof IMap> = IMap[T];
// using
let t: valueof<IMap> = null as any;
let t2: valueof2 = null as any;
但對每一個而言,類型是 IA | IB | IC | ... | IZ,而不是 IA & IB & IC & ... & IZ。
答案#1
這類似於關於如何以程式方式將聯集轉換為交集的問題,並且它有類似的解決方案。
通常當你查找一個物件類型的所有屬性時,你會得到所有屬性的聯集,就像你看到的那樣。問題在於 keyof T 是屬性鍵的 聯集,而查找一個鍵的聯集會給你屬性的聯集,因為屬性查找在屬性鍵類型中是 協變 的……但你想要的是在屬性鍵類型中 逆變 的操作。(你可以在這裡閱讀更多關於協變/逆變的內容,但基本上協變意味著聯合集合作為輸入會變成聯合集合作為輸出,而逆變意味著聯集合輸入會變成交集輸出)。
幸運的是,函數參數是逆變的,所以如果我們能將你的介面映射到一個新的介面,其中舊的屬性類型作為函數參數,我們就可以達到一個地方,使這些函數類型的聯集可以導致其參數的交集。而在條件類型中使用 infer 關鍵字的類型推斷可以為我們做到這一點(參見那行說“如果從逆變位置推斷出了任何候選類型,則推斷的類型是這些候選類型的交集”)。
這是代碼:
type IntersectProperties<T> = { [K in keyof T]: (x: T[K]) => void } extends {
[K in keyof T]: (k: infer I) => void
}
? I
: never;
T 的屬性會對應到函數參數,然後我們會 推斷 一個單一類型 I,對應到 所有的函數參數,這將會是一個交集。
讓我們看看它是否有效:
type IAll = IntersectProperties<IMap>;
// type IAll = IA & IB & IC & ... & IZ
看起來不錯。希望那有幫助;祝你好運!
程式碼連結
