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

Why typescript complains that XXX is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint X?

我的代码是这样的:

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

const createTreeItem = <T extends TreeItem>(): T => {
  return {
    id: 'root',
    children: []
  }
}

但是我在 createTreeItem 的 return 类型上得到一个错误,如下所示:

TS2322: 输入'{ id: string; children: 从不[]; }' 不可分配给类型 'T'。 '{ id: 字符串; children: 从不[]; }' 可分配给 'T' 类型的约束,但 'T' 可以使用约束 'TreeItem'.

的不同子类型实例化

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

有什么帮助吗?

您可以在 return 之后添加“作为 T”:

const createTreeItem = (): T => ({ 编号:'root', children: [] } 作为 T);

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

let node = createTreeItem<TreeItem>()

还好吧? return 类型 TTreeItem,而您的泛型函数被硬编码为 return 的对象实际上有一个类型可以将其限定为 TreeItem

{ id: string; children: never[]; }

但是给你的函数一个类型参数的目的是允许它被其他类型的 T 调用,只要它们扩展 TreeItem。所以下面应该是一个合法的调用:

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

let node = createTreeItem<BidiTreeItem>()

调用是合法的,因为BidiTreeItem满足约束T extends TreeItem。此调用的 return 类型在您的函数定义中声明为 BidiTreeItem,但您的函数 returns 不是 BidiTreeItem.

如果您再次重读错误消息,但考虑到上面的示例,现在您就会明白了。但以防万一,下面我将翻译每一条错误信息。注意第一句是结论,所以放在最后 table:

this part of the error message... means this (using above example)...
'{ id: string; children: never[]; }' is assignable to the constraint of type 'T' '{ id: string; children: never[]; }' is consistent with the constraint T extends TreeItem
but 'T' could be instantiated with a different subtype of constraint 'TreeItem'. but T could be instantiated with a different subtype of TreeItem, for example BidiTreeItem.
TS2322: Type '{ id: string; children: never[]; }' is not assignable to type 'T'. The object your function is returning is not guaranteed to be assignable to type T, because T could be some other subtype such as BidiTreeItem .