typescript类中的自引用数组

typescript类中的自引用数组,typescript,Typescript,我试图用递归数组创建一个类层次结构,该数组本身引用它,但也正确地将类型分配给子类。 我想我很接近了,但是我得到了一个无法解释的TS2351错误 export interface ContentNodeJSON { id: string parentId?: string children: ContentNodeJSON[] } export class ContentNode { id: string parentId?: string children: this[

我试图用递归数组创建一个类层次结构,该数组本身引用它,但也正确地将类型分配给子类。 我想我很接近了,但是我得到了一个无法解释的
TS2351
错误

export interface ContentNodeJSON {
  id: string
  parentId?: string
  children: ContentNodeJSON[]
}

export class ContentNode {
  id: string
  parentId?: string
  children: this[]

  constructor(model: ContentNodeJSON) {
    this.id = model.id;
    this.parentId = model.parentId;
    this.children = model.children.map(child => new this(child));
  }
}
错误如下:

This expression is not constructable.
  Type 'ContentNode' has no construct signatures.  TS2351
    20 |     this.parentId = model.parentId;
  > 21 |     this.children = model.children.map(child => new this(child));
       |                                                     ^
    22 |   }

从构造函数本身调用构造函数是不可能的吗?我是否应该使用其他模式来实现此目标

编辑:

为了澄清我所说的“将类型正确分配给子类”的含义,如果我将子类定义为:

class Page extends ContentNode {}
然后
Page。子项
的类型必须是
Page
,而不是
ContentNode

你可以在
ContentNode.constructor中使用
newcontentnode
,因为在后台它会编译成一个函数(或者更准确地说,它可以看作一个函数,但我离题了),所以它基本上是递归的,JS允许这样做

要回答您的编辑(这是边界a,但无论如何),您可以使用以下泛型类型:

export class ContentNode<T> {
    id: string;
    parentId?: string;
    children: ContentNode<T>[];

    constructor(model: ContentNodeJSON) {
        this.id = model.id;
        this.parentId = model.parentId;
        this.children = model.children.map(child => new ContentNode(child));
    }
}
导出类ContentNode{
id:字符串;
parentId?:字符串;
子节点:ContentNode[];
构造函数(模型:ContentNodeJSON){
this.id=model.id;
this.parentId=model.parentId;
this.children=model.children.map(child=>newcontentnode(child));
}
}

您想调用构造函数,因此它应该是
this.constructor
,而不仅仅是
this
。然而,Typescript似乎不喜欢这样,因为
this.constructor
属于
函数类型,而不是构造函数签名;我不知道为什么Typescript不知道构造函数是构造函数,但我们可以做一个类型断言,说我们知道它是:

const\u constructor=this.constructor as new(…args:any[])=>this;
this.children=model.children.map(child=>new_构造函数(child));
请注意,关于
子对象有点可疑:这个[]
,因为如果
obj
具有类型
ContentNode
,那么您可以编写
obj.children.push(newcontentnode(…)
),并且它将进行类型检查,即使运行时
obj
可能是
页面
实例。通过将其声明为
只读子项:ReadonlyArray
,可以避免此问题


您也在约束子类,使其构造函数接受类型为
ContentNodeJSON
的单个参数,但请注意,此约束在编译时不会被检查。

您还有一个输入错误:
id:string(
children:this[]
应该是
children:ContentNode[]
请参见我在编辑中的评论,将儿童设置为
ContentNode
是行不通的。我不认为这是一个变色龙问题;我从最初的措辞和多态
这种类型的使用中理解了这一要求,我认为这种类型是有意的。我是typescript的新手,所以这种模式可能不是惯用的。它非常复杂在Swift中输入一个集合作为
[Self]
和子类都将在运行时自动推断出正确的类型。我可以看出,当所有类型安全性在运行时消失时,它的价值可能会降低。我编辑过一篇文章,提到您可以声明
只读子类:ReadonlyArray
作为该问题的解决方案。这并不是说数组实际上是不可变的,而是编译器er会检查你没有变异它。
export class ContentNode<T> {
    id: string;
    parentId?: string;
    children: ContentNode<T>[];

    constructor(model: ContentNodeJSON) {
        this.id = model.id;
        this.parentId = model.parentId;
        this.children = model.children.map(child => new ContentNode(child));
    }
}