TypeScript的“扩展”与C#中对泛型的约束不同

时间:2019-03-03 02:12:47

标签: typescript generics

在以下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);
    }
}

非常感谢您的反馈!

1 个答案:

答案 0 :(得分:3)

我不确定C#,但是在TypeScript中,您声明T extends MyClass<T>,这意味着TMyClass<T>子类型与{em> MyClass<T>不相同。因此,类型T的任何值都可以分配给类型MyClass<T>的变量,反之亦然。

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

  childList!: MyClass<T>[];

但就我所知,这可能会在其他地方出现,因为在某些时候您会假设TMyClass<T>相同,事实并非如此。 。您随时可以使用type definition来解决问题,但我认为您可能需要一个完全不同的解决方案:type assertions

使用类型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[];

希望有所帮助;祝你好运!