Skip to content

super keyword allows calling arrow functions defined on the super class, but shouldn't #54900

Closed
@ekilah

Description

@ekilah

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.

Possible duplicates mentioned below

Possible fix mentioned below

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions