简体   繁体   English

Typescript:如何声明代表Treeview的Type? 可能吗?

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

Typescript is a TYPED superset of JavaScript that compiles into JavaScript, fine! Typescript是JavaScript的TYPED超集,可以编译为JavaScript,很好! it helps us to reduce some typos etc etc ok! 它可以帮助我们减少一些错别字等,确定! I want to create an interface that would be used as an argument in a method. 我想创建一个在方法中用作参数的接口。 This interface has to represent a treeview that would be used to parse an object. 该接口必须表示将用于解析对象的树视图。

example: w1[a2].x[b02].yz is the path to access value of z in myObject 示例: 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" } } ] } ] 

What would be the type|interface of treeOfIdentifiers (if not any !) if I code using TypeScript? 接口|什么是类型treeOfIdentifiers (如果没有any如果使用打字稿我的代码!)? The thing is to ensure that each node of treeOfIdentifiers, the property key would be provided and we don't know the structure for the treeOfIdentifiers as we don't know the structure of the object to parse! 这样做的目的是确保将提供 treeOfIdentifiers的每个节点, 属性key并且我们不知道treeOfIdentifiers的结构,因为我们不知道要解析的对象的结构!

This is a fairly difficult thing to express in TypeScript. 这在TypeScript中很难表达。 For example, adding a string-valued property named key to a dictionary of non- string values is not straightforward to strongly type... and possibly implies that you might want to make the type simpler (eg, each node has a key property and a dictionary property). 例如,将名称为key的字符串值属性添加到非string值的字典中并不是很容易强类型化的操作……这可能意味着您可能希望使类型更简单(例如,每个节点都具有key属性和dictionary属性)。

I'm not even thinking of making sure that treeOfIdentifiers is valid when using it to traverse myObject , since you didn't ask about that and this is already very complicated. 我什至没有想到要在使用treeOfIdentifiers遍历myObject时确保其有效,因为您没有对此提出treeOfIdentifiers ,而这已经非常复杂了。

But let's see how far we can get, using mapped and conditional types: 但是,让我们看看使用映射条件类型可以达到的程度:

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;

The trickiest part of that is in NonRootOfTreeOfIdentifiers<T> . 最棘手的部分在NonRootOfTreeOfIdentifiers<T> It takes a type T representing a non-root node in a valid treeOfIdentifiers . 它采用类型T表示有效的treeOfIdentifiers的非根节点。 It adds a key property to T , and then maps these properties of T into a new type: key is mapped as a string property, and every other property is mapped to a NonRootOfTreeOfIdentifiers<> version of itself. 它将一个key属性添加到T ,然后将T这些属性映射到一个新类型: key被映射为一个string属性,而所有其他属性都映射到其自身的NonRootOfTreeOfIdentifiers<>版本。 So NonRootOfTreeOfIdentifiers<T> walks down through the levels of T and converts it to another type. 所以NonRootOfTreeOfIdentifiers<T>通过水平走下T并将其转换为另一种类型。 If T is a valid non-root node, then NonRootOfTreeOfIdentifiers<T> will be a valid non-root node. 如果T是有效的非根节点,则NonRootOfTreeOfIdentifiers<T>将是有效的非根节点。

The TreeOfIdentifiers type function represents the root node, which doesn't require a key property, but otherwise traverses down into NonRootOfTreeOfIdentifiers . TreeOfIdentifiers类型的函数表示根节点,该节点不需要key属性,但否则会遍历到NonRootOfTreeOfIdentifiers

Finally, the asTreeOfIdentifiers function takes an argument of type T which is required to be compatible with TreeOfIdentifiers<T> , and returns the argument. 最后, asTreeOfIdentifiers函数接受类型为T的参数,该参数必须与TreeOfIdentifiers<T>兼容,然后返回该参数。 Meaning, it will only accept objects conforming to the rules. 这意味着,它将仅接受符合规则的对象。 So it validates its argument but doesn't change it. 因此,它验证了其论点,但没有改变。

Let's see if it works: 让我们看看它是否有效:

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

That compiles, and treeOfIdentifiers is inferred to be of type 编译后, treeOfIdentifiers推断为类型

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

If you mess up in some way, you will get errors: 如果您以某种方式搞砸了,则会收到错误消息:

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

or 要么

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>'.

So that all works as far as it goes. 这样一切都可以正常进行。 I'm not sure it's worth it to you, though. 不过,我不确定这是否值得。 It gets even hairier if you try to capture the literal string value types like "idLvlX" (instead of just string ). 如果您尝试捕获诸如"idLvlX"类的文字字符串值类型(而不只是string ),它会变得更加毛茸茸。 And, as I said, I haven't even thought about how you'd validate myObject against treeOfIdentifiers in the type system. 而且,正如我所说,我什至没有考虑过如何针对类型系统中的treeOfIdentifiers验证myObject

Anyway, good luck. 无论如何,祝你好运。 Hope that helped. 希望能有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM