Полиморф c this
на самом деле вам здесь не поможет; нет способа пометить класс как final
в TypeScript так, как вы можете, скажем, Java ... так что всегда возможно, что полиморф c this
должен ссылаться на некоторые суженный тип в некотором пока неизвестном подклассе. Например:
class Foo extends Derived {
map(val: number) {
return "oops";
}
}
new Foo(7).getDefaultVal().toUpperCase(); // error at runtime
Здесь, без ошибок компиляции, расширено Derived
. Но Foo.getDefaultVal()
просто наследует реализацию в Derived
, тип возврата которого предполагается равным DeriveMapVal<this, number>
, где this
будет Foo
на сайте вызова. И DeriveMapVal<Foo, number>
составляет string
. Но реализация Foo
просто возвращает number
, а не string
, поэтому вы получаете сообщение об ошибке: компилятор просто не может проверить, что number
присваивается DeriveMapVal<this, number
>.
Что касается того, как с этим бороться, я думаю, это зависит от того, что вы хотите сделать. Самое простое решение, которое я могу придумать, - это сузить реализацию подкласса, чтобы ссылаться на фактический собственный класс, а не this
:
class Derived extends Generic<number> {
getDefaultVal(): DeriveMapVal<Derived, number> {
return 0; // okay
}
}
Это должно работать, хотя немного странно, что вы все еще можете подкласс Derived
как и прежде, и компилятор правильно видит, что Foo
не может быть назначен на Derived
:
class Foo extends Derived {
map(val: number) {
return "oops";
}
}
new Foo(7).getDefaultVal().toUpperCase(); // error at compile time too, now
const d: Derived = new Foo(10); // error
const g: Generic<number> = new Foo(20); // error
Я имею в виду, class Foo extends Derived
явно не гарантирует, что Foo extends Derived
верно. Странные вещи. Пока вы можете справиться с этой морщинкой, это может быть способом для вас продолжить.
Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код