簡體   English   中英

Typescript:如何聲明代表Treeview的Type? 可能嗎?

[英]Typescript: How to declare a Type which represents a Treeview? Is it possible?

Typescript是JavaScript的TYPED超集,可以編譯為JavaScript,很好! 它可以幫助我們減少一些錯別字等,確定! 我想創建一個在方法中用作參數的接口。 該接口必須表示將用於解析對象的樹視圖。

示例: w1[a2].x[b02].yz是訪問myObjectz值的路徑

 const path = "w1[a2].x[b02].yz"; const treeOfIdentifiers = { "w1": { key: "idLvlW", "x": { key: "idLvlX" } } } const myObject = { w0: "Hello Root", w1: [{ idLvlW: "a1", x: [{ idLvlX: "b01", y: { z: "hello world from w1[a1].x[b01].yz" } }, { idLvlX: "b02", y: { z: "hello world from w1[a1].x[b02].yz" } }, { idLvlX: "b03", y: { z: "hello world from w1[a1].x[b03].yz" } }, { idLvlX: "b04", y: { z: "hello world from w1[a1].x[b04].yz" } } ] }, { idLvlW: "a2", x: [{ idLvlX: "b01", y: { z: "hello world from w1[a2].x[b01].yz" } }, { idLvlX: "b02", y: { z: "hello world from w1[a2].x[b02].yz" } }, { idLvlX: "b03", y: { z: "hello world from w1[a2].x[b03].yz" } }, { idLvlX: "b04", y: { z: "hello world from w1[a2].x[b04].yz" } } ] }, { idLvlW: "a3", x: [{ idLvlX: "b01", y: { z: "hello world from w1[a3].x[b01].yz" } }, { idLvlX: "b02", y: { z: "hello world from w1[a3].x[b02].yz" } }, { idLvlX: "b03", y: { z: "hello world from w1[a3].x[b03].yz" } }, { idLvlX: "b04", y: { z: "hello world from w1[a3].x[b04].yz" } } ] } ] 

接口|什么是類型treeOfIdentifiers (如果沒有any如果使用打字稿我的代碼!)? 這樣做的目的是確保將提供 treeOfIdentifiers的每個節點, 屬性key並且我們不知道treeOfIdentifiers的結構,因為我們不知道要解析的對象的結構!

這在TypeScript中很難表達。 例如,將名稱為key的字符串值屬性添加到非string值的字典中並不是很容易強類型化的操作……這可能意味着您可能希望使類型更簡單(例如,每個節點都具有key屬性和dictionary屬性)。

我什至沒有想到要在使用treeOfIdentifiers遍歷myObject時確保其有效,因為您沒有對此提出treeOfIdentifiers ,而這已經非常復雜了。

但是,讓我們看看使用映射條件類型可以達到的程度:

type NonRootOfTreeOfIdentifiers<T> = { [K in 'key' | keyof T]:
  K extends 'key' ? string :
  K extends keyof T ? NonRootOfTreeOfIdentifiers<T[K]> : never
};
type TreeOfIdentifiers<T> = { [K in keyof T]: NonRootOfTreeOfIdentifiers<T[K]> };
const asTreeOfIdentifiers = <T extends TreeOfIdentifiers<T>>(t: T): T => t;

最棘手的部分在NonRootOfTreeOfIdentifiers<T> 它采用類型T表示有效的treeOfIdentifiers的非根節點。 它將一個key屬性添加到T ,然后將T這些屬性映射到一個新類型: key被映射為一個string屬性,而所有其他屬性都映射到其自身的NonRootOfTreeOfIdentifiers<>版本。 所以NonRootOfTreeOfIdentifiers<T>通過水平走下T並將其轉換為另一種類型。 如果T是有效的非根節點,則NonRootOfTreeOfIdentifiers<T>將是有效的非根節點。

TreeOfIdentifiers類型的函數表示根節點,該節點不需要key屬性,但否則會遍歷到NonRootOfTreeOfIdentifiers

最后, asTreeOfIdentifiers函數接受類型為T的參數,該參數必須與TreeOfIdentifiers<T>兼容,然后返回該參數。 這意味着,它將僅接受符合規則的對象。 因此,它驗證了其論點,但沒有改變。

讓我們看看它是否有效:

const treeOfIdentifiers = asTreeOfIdentifiers({
  "w1": {
    key: "idLvlW",
    "x": {
      key: "idLvlX"
    }
  }
});  

編譯后, treeOfIdentifiers推斷為類型

{
    "w1": {
        key: string;
        "x": {
            key: string;
        };
    };
}

如果您以某種方式搞砸了,則會收到錯誤消息:

const missingKey = asTreeOfIdentifiers({
  "w1": {
    key: "idLvlW",
    "x": {
      kee: "idLvlX" // oops
    }
  }
}); 
// error: Property 'key' is missing in type '{ kee: string; }'

要么

const extraProperty = asTreeOfIdentifiers({
  "w1": {
    key: "idLvlW",    
    x: {
      key: "idLvlX"
    }
    y: 123 // oops
  }
}); 
// error: Types of property 'y' are incompatible.
//  Type 'number' is not assignable to type 'NonRootOfTreeOfIdentifiers<number>'.

這樣一切都可以正常進行。 不過,我不確定這是否值得。 如果您嘗試捕獲諸如"idLvlX"類的文字字符串值類型(而不只是string ),它會變得更加毛茸茸。 而且,正如我所說,我什至沒有考慮過如何針對類型系統中的treeOfIdentifiers驗證myObject

無論如何,祝你好運。 希望能有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM