Description
Bug Report
🔎 Search Terms
super should not expose or allow call to superclass instance arrow function in subclass
🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about
super
⏯ Playground Link
Playground link with relevant code
💻 Code
class Animal {
makeNoise = () => console.log('animal noises')
}
class Dog extends Animal {
makeNoise = () => super.makeNoise()
}
const d = new Dog()
d.makeNoise()
Output
"use strict";
class Animal {
constructor() {
this.makeNoise = () => console.log('animal noises');
}
}
class Dog extends Animal {
constructor() {
super(...arguments);
this.makeNoise = () => super.makeNoise();
}
}
const d = new Dog();
d.makeNoise();
Compiler Options
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"alwaysStrict": true,
"esModuleInterop": true,
"declaration": true,
"target": "ES2017",
"jsx": "react",
"module": "ESNext",
"moduleResolution": "node"
}
}
Playground Link: Provided
🙁 Actual behavior
The TS compiler does not give any warnings or errors, and this code crashes at runtime.
[ERR]: "Executed JavaScript Failed:"
[ERR]: super.makeNoise is not a function
🙂 Expected behavior
The TS compiler should not allow me to call super.makeNoise
if Animal
's makeNoise
is an instance property/function, since only class methods will be on the prototype that super
will access.
TS docs on why super
doesn't work in practice here: https://www.typescriptlang.org/docs/handbook/2/classes.html#arrow-functions
A note on why I care
Obviously the example is oversimplified. How I got here: I am trying to get contravariant type checking on subclass overrides of abstract super class functions, and as discussed in several places (below are some examples), you can only achieve this with superclass abstract instance properties that are functions (and not with abstract class methods):
But I would also like to let these subclasses sometimes call a superclass's default implementation (i.e. make some of the superclass methods not abstract
but still overridable, and let them call super.foo()
to defer to the default implementation if they choose to along with other logic).
It seems like I am stuck wanting two things, when I'm only allowed to have one: either contravariant type checking via instance property functions that can't be referred to by the subclass via super
, or overridable-but-defined superclass class methods whose subclass overrides are bivariantly checked.
I decided that contravariant type checking was more important to me, and I decided I'd get rid of the super
calls everywhere -I found several type errors/small bugs in our codebase when I switched things over to instance property functions (mostly copy/paste errors or mistakes in generics on the class definition that weren't being caught in a bivariant world), and I was excited to try and get rid of the possibility for these mistakes going forward.
However, I am concerned that the compiler won't stop my coworkers (or my future self) from exercising muscle memory in calling super
in no-longer-method subclass overrides of instance property functions, which we've been doing for some time. Even if I find them all without the compiler's help now, the bug I'm reporting here prevents me from having any protection against regressions!
Related issues
None of these are quite on the same topic, but they are in the same realm.
- Strict function types #18654
- Methods are not accepted as implementation of abstract members with function type #51261
- Subclass method is not allowed (TS2425) if the parent class has a property of type any with the same name #27965
Possible duplicates mentioned below
- The child class should not be able to access the class field defined by the parent class via super #54054
- Accessing property on super should be a type error #35314