【发布时间】:2021-04-29 14:52:42
【问题描述】:
我有以下代码:
abstract class TreeNode<Type extends TreeNode<Type>> {
children: Type[];
protected constructor() {
this.children = [];
}
addSelfToParent(parent: Type) {
parent.children.push(this as Type);
}
// ...
}
typescript 编译器在 this as Type 部分发出以下错误。
TS2352: Conversion of type 'this' to type 'Type' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
'this' is assignable to the constraint of type 'Type', but 'Type' could be instantiated with a different subtype of constraint 'TreeNode<Type>'.
Type 'TreeNode<Type>' is not comparable to type 'Type'.
'Type' could be instantiated with an arbitrary type which could be unrelated to 'TreeNode<Type>'.
当我用this as unknown as Type 替换零件时,错误消失了。
我对错误消息中的“无关”部分特别困惑。
问题:它怎么可能是“不相关”的类型? Type 被定义为TreeNode<Type> 的扩展类型。
TypeScript 版本是 4.1.5。
更新 1
添加示例代码以回答 Linda Paiste 的问题。
首先,带有更多示例代码的原始类代码(并修复了as 错误)。
abstract class TreeNode<Type extends TreeNode<Type>> {
children: Type[];
protected constructor() {
this.children = [];
}
addSelfToParent(parent: Type) {
parent.children.push(this as unknown as Type);
}
// ...
}
class TreeNodeWithValue extends TreeNode<TreeNodeWithValue> {
value: number;
constructor() {
super();
this.value = 1;
}
}
function sumValuesOfChildren(node: TreeNodeWithValue) {
let sum = 0;
for (let i = 0; i < node.children.length; i++)
sum += getChildValue(node.children[i]);
console.log(sum);
}
function getChildValue(node: TreeNodeWithValue) {
return node.value;
}
在这里,可以调用 getChildValue() 而不会出现任何打字错误。
但是当 'extends ...' 被如下删除时,
abstract class TreeNode<Type>
{
children: TreeNode<Type>[];
protected constructor() {
this.children = [];
}
addSelfToParent(parent: TreeNode<Type>) {
parent.children.push(this);
}
}
class TreeNodeWithValue extends TreeNode<TreeNodeWithValue> {
value: number;
constructor() {
super();
this.value = 1;
}
}
function sumValuesOfChildren(node: TreeNodeWithValue) {
let sum = 0;
for (let i = 0; i < node.children.length; i++)
sum += getChildValue(node.children[i]);
console.log(sum);
}
function getChildValue(node: TreeNodeWithValue) {
return node.value;
}
Typescript 编译器在 getChildValue(node.children[i]) 上发出以下错误。
TS2345: Argument of type 'TreeNode<TreeNodeWithValue>' is not assignable to parameter of type 'TreeNodeWithValue'.
Property 'value' is missing in type 'TreeNode<TreeNodeWithValue>' but required in type 'TreeNodeWithValue'
我可以通过像这样向下转换来避免错误:getChildValue(node.children[i]) as TreeNodeWithValue。
但我不希望这种沮丧。向下转换有效地消除了泛型本身的意义。为此,我不得不添加(丑陋的)“扩展……”。
更新 2
kaya3的建议大抵可行,但如果在子类中添加处理children属性的方法就不行了,如下:
abstract class TreeNode {
children: this[];
protected constructor() {
this.children = [];
}
addSelfToParent(parent: this) {
parent.children.push(this);
}
}
class TreeNodeWithValue extends TreeNode {
value: number;
constructor() {
super();
this.value = 1;
}
addChild() {
this.children.push(new TreeNodeWithValue()); // ERROR
}
}
错误如下:
TS2345: Argument of type 'TreeNodeWithValue' is not assignable to parameter of type 'this'.
'TreeNodeWithValue' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'TreeNodeWithValue'.
【问题讨论】:
-
extends真的有必要吗?abstract class TreeNode<Type> { children: TreeNode<Type>[]; addSelfToParent(parent: TreeNode<Type>) { parent.children.push(this); } }根本不需要任何断言 -
@LindaPaiste 谢谢。我添加了相关的示例代码和一些解释。请参阅“更新”部分。
-
顺便说一句,您的代码中有很多突变。 TS 不适合他们。
标签: typescript