我正在嘗試改編我已經在TypeScript中編寫的現有流程,使其具有更強的類型。使用TypeScript指定複雜的樹處理規則
基本上,我有一個樹狀結構,看起來像這樣:
interface Node {
[name: string]: Leaf | Node | Node[] | undefined;
}
這是一個簡單的樹,其中每個節點都包含無論是葉節點,另一個節點,節點列表,或不確定的,由組織屬性名稱。
我有一個機制,可以在這棵樹上運行規則。規則是這樣的:
interface Rule<T extends Node, K = keyof T> {
name: K;
optional?: boolean;
data?: {}; // matches against the structure of a child Leaf
list?: boolean; // whether this child should be a list
process?(processor: RuleProcessor): Node; // for processing sub-nodes
// ...other flags and stuff specific to the rule
}
我想通過指定適用於不同類型的兒童單獨類型的規則,使這個更通用:
optional
僅適用於兒童,可能是未定義data
僅適用於有葉的孩子list
只適用於那些列表(在這種情況下,它總是爲真) 兒童
process()
只適用於那些節點或節點列表兒童
這就是我設想:
type Child = Leaf | Node | Node[];
interface Node {
[name: string]: Child | undefined;
}
interface Rule<T extends Node, K extends keyof T = keyof T, _V extends T[K] = T[K]> {
name: K;
}
interface OptionalRule<T extends Node, K extends keyof T = keyof T> extends Rule<T, K, Child | undefined> {
optional: true;
}
interface RequiredRule<T extends Node, K extends keyof T = keyof T, V extends Child = Child> extends Rule<T, K, V> {}
interface LeafRule<T extends Node, K extends keyof T = keyof T> extends RequiredRule<T, K, Leaf> {
data: {};
}
interface ListRule<T extends Node, K extends keyof T = keyof T> extends RequiredRule<T, K, Node[]> {
list: true;
}
interface ProcessRule<T extends Node, K extends keyof T = keyof T> extends RequiredRule<T, K, Node | Node[]> {
process(processor: RuleProcessor): Node;
}
type AnyRule<T extends Node> = OptionalRule<T> | LeafRule<T> | ListRule<T> | ProcessRule<T>;
function process<T extends Node>(node: T, rules: AnyRule<T>[]) {
// logic
}
的想法是,如果我指定的規則特定屬性,該選擇的規則類型將會檢查該屬性的類型。
例如,說我有一個節點:
const node: Node = { a: new Leaf(), b: [] };
我對其進行處理:
process(node, [{ name: 'a', data: {} }, { b: list: true }]);
我期望指定data
將檢查以某種方式確保node['a']
是Leaf
,如果不是,則會發出錯誤。同樣,第二條規則會檢查以確保node['b']
是Node[]
。
但是,當我將data: {}
更改爲list: true
,a
時,即使node['a']
不是數組,也不會發生錯誤。我知道我從一開始就做錯了什麼,但是我想知道在TypeScript中是否有這樣的事情是可能的。我知道有很多這些新功能,如keyof T
和T[K]
,我們能夠描述一些相當複雜的類型,所以我希望能夠實現我想要做的。
我的目標是將編譯時間檢查到位,以便開發人員不會犯任何錯誤。很明顯,這些都不需要在運行時應用,因爲類型都被剝離了。
編輯:基本上這個問題將被解決,如果有一種方法可以讓我在V = T[K]
上設置一個約束,即V
必須是特定類型。