I have this valid JavaScript code:
class Base {
// Base has an accesor in the prototype
get foo() {
return "getter Base";
}
}
class Deriv extends Base {
// I want define here an own property, hiding the access to the getter,
// but in TypeScript...
// ERROR: 'foo' is defined as an accessor in class 'Base', but is
// overridden here in 'Deriv' as an instance property. (2610)
foo = "prop Deriv";
}
Using useDefineForClassFields: true.
What I'm trying to do
Basically I want a base class to have a getter in the prototype and then be able to define an own property (enumerable) in a derived class. I think there are very valid reasons to do that, like having a default algorithm in the base class (or exposing some private state, etc.) but replacing it with a property defined in an instance of a derived class.
TypeScript fails with an error TS2610 as shown in the snippet. I remember seeing the pull request that made this case an error, I don't remember right now the number (think is #37894). I understand this code is using [[Define]] semantics so if I have a setter for that property in the base class it won't be called. But that's exactly what I want!, however TS complains.
What I've tried
Declaration merging with an interface but the error persists:
class Base {
get foo() { return "getter Base"; }
}
interface Deriv {
readonly foo: string; // Same error here...
}
class Deriv extends Base {}
Defining the property in the constructor via Object.defineProperty. It works, of course, since TS doesn't check that, but now the types are lying because the derived class is "inheriting" the getter declaration from the base type. For instance the inferred type for o in const o = { ...new Deriv() } doesn't include foo since is a getter in the prototype.
// @ts-ignore. Of course it works, but I think there's no reason to comment more on this...
Using declare readonly foo: string in the derived class. I imagined it wouldn't work but was worth trying. Got same error.
Questions / Final comments
Is there a better way to do this?
If I remember the original PR correctly the rationale behind it was to prevent a developing surprise with the change from [[Set]] to [[Define]] semantics. The issue is that I cannot find a good way to opt-in this behavior with good typings.
Related links:
PR: Always error on property override accessor
Issue: Proposal: allow ambient property declarations to override accessors as well