为什么打字稿抱怨 XXX 可分配给类型“T”的约束,但“T”可以用约束 X 的不同子类型实例化?

ent*_*one 6 javascript interface typescript typescript-generics

我的代码是这样的:

\n
export interface TreeItem {\n  id: string;\n  children: this[];\n  collapsed?: boolean;\n}\n\nconst createTreeItem = <T extends TreeItem>(): T => {\n  return {\n    id: 'root',\n    children: []\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但我收到一个错误,其返回类型createTreeItem如下:

\n
\n

TS2322: 类型“ { id: string; children: never[]; }”不可分配给\n类型“ T”。\xc2\xa0\xc2\xa0' { id: string; children: never[]; }' 可分配给\n类型“ ”的约束T,但“ T”可以使用不同\n约束子类型' 进行实例化TreeItem

\n
\n

我完全不知道这是什么意思。

\n

有什么帮助吗?

\n

vas*_*vas 9

假设您按如下方式调用函数:

let node = createTreeItem<TreeItem>()
Run Code Online (Sandbox Code Playgroud)

一切都很好,对吧?返回类型TTreeItem,并且泛型函数硬编码返回的对象实际上具有将其限定为 的类型TreeItem

{ id: string; children: never[]; }
Run Code Online (Sandbox Code Playgroud)

但为函数提供类型参数的目的是允许使用其他类型的 来调用它T,只要它们扩展即可TreeItem。所以以下应该是合法的调用:

export interface BidiTreeItem {
  id: string;
  children: this[];
  parent: this;
  collapsed?: boolean;
}

let node = createTreeItem<BidiTreeItem>()
Run Code Online (Sandbox Code Playgroud)

该调用是合法的,因为BidiTreeItem满足约束T extends TreeItem。正如函数定义中声明的那样,此调用的返回类型是BidiTreeItem,但函数返回的不是BidiTreeItem

如果您再次重读错误消息,但记住上面的示例,现在您就会明白了。但为了以防万一,下面我将翻译每一条错误消息。请注意,第一句话是结论,因此它将在此表中放在最后:

错误消息的这一部分... 意思是(使用上面的例子)...
'{ id: string; children: never[]; }' is assignable to the constraint of type 'T' '{ id: string; children: never[]; }' 与约束条件一致T extends TreeItem
but 'T' could be instantiated with a different subtype of constraint 'TreeItem'. T可以用不同的子类型来实例化TreeItem,例如BidiTreeItem.
TS2322: Type '{ id: string; children: never[]; }' is not assignable to type 'T'. 您的函数返回的对象不能保证可分配给 type T,因为T可能是其他一些子类型,例如 BidiTreeItem.

  • @captain-yossarian,很好!顺便说一句,您对我要求 Typescript 人员制作措辞更好的错误消息有何看法?我在想这样的事情: *“你犯了两个经典错误之一!第一个错误是从未设置`noImplicitAny: false`,但只是稍微鲜为人知:在输入时永远不要违反参数化返回类型约束安全就在一线!哈哈哈哈哈哈\*程序死掉\*"* (4认同)