網站搜尋

typescript - 從聯合類型中過濾掉具有已知鍵以外任意鍵的對象


給定像這樣的類型

type Test = { name: "a" } | { name: "b" } | { name: "c", other: 1 } | { name: "d", other: 2 }

我如何過濾出聯合類型中包含除「name」之外的鍵的類型。所以在這個例子中,結果類型將是 { name: "a" } | { name: "b" }。

這裡有一個 TS Playground:https://www.typescriptlang.org/play?#code/C4TwDgpgBAKhDOwoF4oG8oDsCGBbCAXFAETbFQC+UAPulnoSQEblW0Y75HEDGxANFAD2wABYQATkQCMlGnU6NiAEwHCxkogCZKAKF2hIUAGIBLADbBJEZXEQoo2TCH3mISAB5Ezl67YRIqBwM3HyCIuJSULJUAPSxUACiEhJCErpuSCDeFlYSNnaBCiEkZHLxJqaYEEA

答案#1

處理這類事情的一般方法是撰寫一個分配條件型別,將聯合輸入型別拆分成其各個成員,然後單獨保留或丟棄每個成員,之後再將它們重新合併成另一個聯合型別。這裡有一個可能的做法:

type Filter<T> = T extends unknown ?
    Exclude<keyof T, "name"> extends never ? T : never
    : never

所以 T extends unknown ? ⋯ : never 在泛型類型參數 T 上會分配到聯合類型。我使用的特定篩選器是 Exclude<keyof T, "name"> extends never ? T : never。Exclude<X, Y> 工具類型會移除與 Y 匹配的 X 的聯合成員,因此 Exclude<keyof T, "name"> 是 T 中不是 name 的鍵的聯合。如果該聯合為空(也就是不可能的 never 類型),那麼我們希望保留 T;否則我們就丟棄它。

好,我們來測試看看:

type Test = { name: "a" } | { name: "b" } |
{ name: "c", other: 1 } | { name: "d", other: 2 }

type FilteredTest = Filter<Test>;
/* type FilteredTest = { name: "a"; } | { name: "b"; } */

let x: FilteredTest = { name: "c", other: 1 } // Error
let y: FilteredTest = { name: "a" } // Fine

看起來不錯!

程式碼的 Playground 連結