首页 > 解决方案 > TypeScript 中的“扩展”与 C# 中对泛型的约束不同

问题描述

在以下 TypeScript 代码中的“this”上,我收到以下错误:

“this”类型的参数不能分配给“T”类型的参数。类型“MyClass”不可分配给类型“T”.ts(2345)

用 TypeScript 3.2.2 编写(在 Angular 7 中)

export abstract class MyClass<T extends MyClass<T>> {

    childList: T[];

    foo = () => {
            const index = this.childList.indexOf(this);
            // ...
    }
}

这就是我用 C# 编写它的方式:

public abstract class MyClass<T> where T : MyClass<T>
{
    public T[] childList { get; set; }

    public void foo()
    {
        int index = Array.IndexOf(childList, this);
    }
}

非常感谢任何反馈!

标签: typescriptgenerics

解决方案


我不确定 C#,但在 TypeScript 中,您声明的是T extends MyClass<T>,这意味着它T是 的子类型MyClass<T>. MyClass<T>因此,任何类型的值T都可以分配给类型的变量MyClass<T>,但反之则不行。

类型定义Array<X>.indexOf(y)期望y可分配给,X反之亦然。所以调用Array<T>.indexOf()类型参数是错误的MyClass<T>。解决此问题的一种方法是声明childList为 typeArray<MyClass<T>>而不是Array<T>

  childList!: MyClass<T>[];

但据我所知,这会在其他地方显示为一个问题,因为在某些时候你会想假设它T与 相同MyClass<T>,但事实并非如此。您始终可以使用类型断言来解决问题,但我认为您可能需要一个完全不同的解决方案:多态this

与其尝试表示循环/递归类型Foo<T extends Foo<T>>,如追逐自己的尾巴,不如使用类型this来表示“当前类的类型”。你的MyClass变成:

export abstract class MyClass {

  childList!: this[];

  foo() {
    const index = this.childList.indexOf(this); // okay
  }
}

子类或多或少按照您期望的方式工作:

export class MyConcreteClass extends MyClass {
  bar() {
    this.childList.indexOf(this); // still works
  }
}

并且实例兑现this为实例的实际类型:

const y = new MyConcreteClass();
y.childList; // type MyConcreteClass[];

希望有帮助;祝你好运!


推荐阅读