In TypeScript, I want a given subclass to implement a static method which would be called by the superclass. This method returns data that is really a property of the class and not of an instance and thus makes sense as static rather than non-static from a modeling point of view.
What I'm currently doing in the superclass to call the static method defined in the subclass is this:
const r = Object.getPrototypeOf(this).constructor.staticMethod()
First question: is there a better way to do this? In particular, constructor returns any, which I never like.
Second: how can I ensure at compile-time that the subclass will implement the static method staticMethod? I've tried various approaches, including stuff with satisfies like
type SuperclassStatic = { someMethod(): number }
const Subclass = class extends Superclass { ... } satisfies SuperclassStatic
… but not only does this seem to be invalid syntax in TypeScript 4.9.5, it is also not great that I'd have to remember to add the satisfies SuperclassStatic part in every subclass declaration.
Any better way?
If this is within an instance method of the superclass (which you've confirmed in a comment it is), then while you don't have to use
Object.getPrototypeOf, you are sadly stuck withthis.constructor, which as you say isn't ideal as its type is justFunction:(Note: The
!ctor.staticMethodcheck above only makes sense in conjunction with another change I make below [making the parent class use a different name for the static method than subclasses]. If you don't make that change, you might doif (ctor.staticMethod === Parent.staticMethod) {instead for the condition of thatifthat will throw on an invalid subclass.)I don't think you can if the names are the same, but if you make the names different it's possible with the help of a do-nothing function so we can use a generic to do the check (here I've made the superclass method's name
parentStaticMethod, with the subclasses expected to implementstaticMethod):Playground link
validSubdoesn't have to be a method onParent, but it seemed a reasonable place to put it. It could be a standalone function instead.Of course, using that
Parent.validSubis a pain and easily forgotten. :-| I thought we might be able to useimplementsinstead of a function (similar to this answer), but if so, I can't get it to work, and in any case it would also (as you say) be a pain and easily forgotten.