Skip to content

Access base class protected methods in static block #62738

Description

🔍 Search Terms

  • Dynamic method override
  • Static block super
  • Static block prototype

✅ Viability Checklist

⭐ Suggestion

Hey there, I have a use case where I want to declare/override a protected method using it's prototype.

With the addition of static blocks I can now override the method itself, however I can't call the same method of the base class using super. This makes it impossible to create dynamic overrides of a prototype method atm.

My suggestion would be to allow the usage of the base type prototypes in a static block of the class as well.
This would make it a lot easier to dynamically override/declare a method without using instance fields.

📃 Motivating Example

TypeScript now supports dynamic method overrides using static initialization blocks instead of runtime checks.

💻 Use Cases

1. What do you want to use this for?
Dynamic method declarations / overrides
Dynamic class creation using an options object.

2. What shortcomings exist with current approaches?
Currently the only way I see to do this is either:

  • Use as any/ which destroys type information
  • Use as DerivedType which allows the call with type information
  • Always override the method and call the additional method in an if branch which usually requires an instance field
  • Declare the method on an instance field instead of the prototype which uses more memory
  • Use ts-ignore because you know what you are doing

3. What workarounds are you using in the meantime?

  • I use (Base.prototype as DerivedType).myMethod which imho is the best solution atm

Example:
https://www.typescriptlang.org/play/?ssl=25&ssc=2&pln=1&pc=1#code/MYGwhgzhAECyCeBhcVoG8BQ1oAcBOA9gC4CmwpAJtALbywlEAWBFAFAJTpbbQD0v0AHTCIBaiWggCAcwCWwbgF8MyjKEgwEAERJ5ZANxIVkG6CQAepAHYVNSFBEzZ8xMpWgFDePRQm16TCwcXDx8AsKC0KLi0GAUFLJEsgRWYCCSMvLc2BAArji6gv4MzGzsShjcEERgScAhPEyyEIIuRMTwBUV0JSzQALzQAGa5VuTJVqxNEABccPA6eobGDpxOoWFCwlFiEnEJSSlpGXIK2Tx5BXjdAaXB-FH5utCjvup4RtBEEABMAGx-AAMlQ28xMUFahHaRE6JBuvQogmAaRAU0YzXYAG5NlZiLEQFIAO6fb4-AAsZL+II2rAQ4JabQ6BViMDAVng7HhgURyIJaIxmwAKuiYISCHgANYwABGuSI0GaLysEDAQxI52wtPsGkhxCZezsiwMRnpnOK3KRKP5EE4D2FirFkplcoVMFGKrV52U2GUiiAA

Activity

  1. dotlogix commented on Nov 9, 2025

    @dotlogix
    Author

    Btw the compiler suggestions to use the derived type is also misleading as it does not have the same runtime behaviour:

    Property 'myMethod' is protected and only accessible through an instance of class 'MyDerivedClass'. This is an instance of class 'MyClass'.(2446)
    

    For me this sounds like I could do the same using 'MyDerivedClass' but this would end up in an infinite recursive call

  2. jcalz commented on Nov 9, 2025

    @jcalz
    Contributor

    Your example is a bit weird.

    // not allowed ts2339 is a typo, right? You mean ts2349? But that's just because you left out a semicolon and you relied on ASI to insert it, and it didn't. Put in the semicolon and you get an actual error you're presumably trying to talk about, ts2446.

    And the error on super is a good one. If you run that code using any runtime that supports static blocks you'll get an error like use of super property accesses only valid within methods or eval code within methods. You want TS to issue an error there because you're trying to avoid a runtime error.

    Maybe you could edit your examples (and include them as plaintext) to focus on the issue you're facing?

  3. dotlogix commented on Nov 9, 2025

    @dotlogix
    Author

    Here the example in plain text:

    class MyClass {
      protected myMethod() {
        // ...some logic
      }
    }
    
    class MyDerivedClass extends MyClass{
      protected override myMethod() {
        // ... some additional logic
        super.myMethod()
      }
    
      static {
        this.prototype.myMethod = function(this: MyDerivedClass) {
          // ... some additional logic
    
          super.myMethod() // super undeclared ts2660
    
          MyClass.prototype.myMethod.call(this); // not allowed ts2446
    
          (MyClass.prototype as any).myMethod.call(this) // This works but is unsafe
          (MyClass.prototype as MyDerivedClass).myMethod.call(this) // This works but is unsafe
        }
      }
    }

    However I found an 'elegant' solution I guess:

    class MyDerivedClass extends MyClass{
      protected override myMethod() {
        // ... some additional logic
        super.myMethod()
      }
    
      static {
        const base = this.prototype.myMethod;
        this.prototype.myMethod = function(this: MyDerivedClass) {
          // ... some additional logic
          base.call(this);
        }
      }
    }

    This is I think the correct solution anyway because it properly infers the types and also also does not need direct access to the base type. So maybe it is fine as is, did not think about that I could just store the existing method as a temp variable.

  4. RyanCavanaugh commented on Nov 10, 2025

    @RyanCavanaugh
    Member

    🤖 Thank you for your issue! I've done some analysis to help get you started. This response is automatically generated; feel free to 👍 or 👎 this comment according to its usefulness.

    Similar Issues

    Here are the most similar issues I found

    If your issue is a duplicate of one of these, feel free to close this issue. Otherwise, no action is needed.

  5. RyanCavanaugh commented on Nov 11, 2025

    @RyanCavanaugh
    Member

    This specific error seems wrong

    MyClass.prototype.myMethod.call(this); // not allowed ts2446

  6. Andarist commented on Nov 12, 2025

    @Andarist
    Contributor

    This error message ain't the best either:

    class OtherClass {
      protected myMethod() {}
    }
    
    class OtherDerivedClass extends OtherClass {
      someMethod(a: OtherClass) {
        // Property 'myMethod' is protected and only accessible through an instance of class 'OtherDerivedClass'. This is an instance of class 'OtherClass'.(2446)
        a.myMethod();
      }
    }

    The mention of OtherDerivedClass in the context of this error message feels confusing.

  7. added a commit that references this issue on Nov 13, 2025
    5cf79d7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: classesBehavior of various `class` constructs, e.g. mixins or base classesHelp WantedYou can do this

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions