Reputation: 2185
This is really hard to describe in words, but essentially I want to have a base abstract class that describes an abstract interface that needs to change depending on whether or not a derived class is implementing a certain interface or not.
Here's a TS playground showing the issue - everything is working fine, and the types are correct outside of the class, but internally typescript is reporting type errors.
Upvotes: 2
Views: 245
Reputation: 329553
Polymorphic this
is not really helping you here; there's no way to mark a class as final
in TypeScript the way you can in, say, Java... so it's always possible that polymorphic this
has to refer to some narrowed type in some as-yet-unknown subclass. For example:
class Foo extends Derived {
map(val: number) {
return "oops";
}
}
new Foo(7).getDefaultVal().toUpperCase(); // error at runtime
Here we have, with no compiler errors, extended Derived
. But Foo.getDefaultVal()
is just inheriting the implementation in Derived
, whose return type is supposed to be DeriveMapVal<this, number>
, where this
is going to be Foo
at the call site. And DeriveMapVal<Foo, number>
is string
. But Foo
's implementation is just returning a number
and not a string
, which is why you're getting the error: the compiler simply cannot verify that number
is assignable to DeriveMapVal<this, number
>.
As for how to deal with it, I guess it depends on what you want to do. The easiest solution I can think of is to narrow the subclass implementation to refer to the actual self-class and not this
:
class Derived extends Generic<number> {
getDefaultVal(): DeriveMapVal<Derived, number> {
return 0; // okay
}
}
This should work, although it's a bit strange that you can still subclass Derived
as before, and the compiler correctly sees that Foo
is not assignable to 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
I mean, class Foo extends Derived
apparently does not guarantee that Foo extends Derived
is true. Weird stuff. As long as you can handle that wrinkle then this might be a way for you to proceed.
Okay, hope that helps; good luck!
Upvotes: 1