TypeScript: Missing property declaration in abstract class implementing interfaces
Abstract class should not be required to implement all the properties/methods of the interfaces it implements. So the following should be legal:
interface A {
p;
m();
}
abstract class B implements A {
}
class C extends B {
get p() {...};
set p(v) {...};
m() {...}
}
But currently it gives:
Error:(2, 16) TS2420: Class ‘B’ incorrectly implements interface ‘A’. Property ‘p’ is missing in type ‘B’.
This issue is related to proposal #3578.
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Reactions: 29
- Comments: 15 (4 by maintainers)
Just ran into this, was very surprised by the behaviour. Why an already abstract class needs to redefine interface methods as abstract is beyond me.
@mhegazy I used to think that abstract classes are just like interfaces but with some members implemented. I know that TypeScript very often works non-intuitively different from other languages, but that is the difference in this specific case comparing to languages that don’t have such problems with abstract classes?
If you describe the problem with a concrete example I will appreciate this very much.
Although, the convenience of not writing the declaration would be nice, the possible confusion/complexity arising from this change would not warrant it. by examine the declaration, it is not clear which members appear on the type, is it all properties, methods, or properties with call signatures; would they be considered abstract? optional?
For a motivating example:
Of course we can keep declaring setEnabled in each derived class as an instance property
setEnabled: (value: boolean) => void;and then add it to each prototype with a mixin, but it would’ve been nice for ABCs to do this automatically. It limits the usefulness of ABCs severely if they can only reference their own members.And you can’t work around this by adding stubs
enable: () => void; disable: () => void;to the ABC to satisfy the interface because the derived class then can’t implement them as methods:error TS2425: Class 'BaseClock' defines instance member property 'enable', but extended class 'DerivedClock1' defines it as instance member function.A workaround that continues to use ABCs is to implement everything in the ABC and duplicate everything that needs to be implemented in derived classes as abstract protected methods, which is ugly as hell.
I agree that this behavior is a bit unexpected. As an alternative, I’ve been getting around this using interface merging.
The code below results in a compile time error:
I’ve been avoiding the compile time error by using something like this instead:
I agree that this behavior is very unexpected.
Just small question, because this is for me probably most annoying feature of TypeScript - how much of you are using TS with PHP, thus you have a “compact” abstracts with the “heavy” ones on TS side?
I have one general usage patter:
I would be really happy too to not be forced to reuse all methods from interfaces in abstracts.
quite surprising behavior for me as well - don’t think that it would introduce any risks, at least for scenarios that @mhegazy has mentioned. Actually, it could be much more easier for the code reader to dissect all the different methods and understand which particular behavior aspects where introduced either by interface or abstract class. And from the maintenance perspective, as @Arnavion has already mentioned here, it would be an additional work required to be done each time you’ll change the interface - it would require additional changes in the abstract class which, in fact, should just introduce its behavior aspects which it is responsible for and, thus, it should not be touched each time the interface has changed.