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

问题描述 投票:0回答:2

我的代码是这样的:

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

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

但是我在

createTreeItem
的返回类型上得到一个错误,如下所示:

TS2322: 输入 '{ id: string;孩子们:从不[]; }' 不可分配给类型 'T'。 '{ id: 字符串;孩子们:从不[]; }'可分配给类型'T'的约束,但'T'可以用约束'TreeItem'的不同子类型实例化。

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

有什么帮助吗?

javascript typescript interface typescript-generics
2个回答
7
投票

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

let node = createTreeItem<TreeItem>()

好吧?返回类型

T
TreeItem
,而您的泛型函数被硬编码为返回的对象实际上有一个类型可以将其限定为
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
。此调用的返回类型,如您的函数定义中所声明的,是
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'.
您的函数返回的对象不能保证可分配给类型
T
,因为
T
可能是其他一些子类型,例如
BidiTreeItem
.

-2
投票

您可以在返回后添加“

as T
”:

  const createTreeItem = <T extends TreeItem>(): T => ({
      id: 'root',
      children: []
  } as T);
© www.soinside.com 2019 - 2024. All rights reserved.