15

Given

class BaseClass{

  count:number=0;

  public someMethod=():void =>{
      this.count++;
  }
}

class ChildClass extends BaseClass{
  public someMethod=():void=>{
     super.someMethod();
     //Do more work here.
  }
}

I receive the error message:

Only public methods of the base class are accessible via the 'super' keyword.

@Basarat provides some information here but this seems like a real hack to the language. typescript arrow operator to define a function on prototype

How might this be done while preserving contextual use of 'this'?

Am I using arrow functions properly or should they really only be used as a method of declaring something like a callback?

5
  • I am sure you already know ... but still wanted to share (hence a comment : youtube.com/watch?v=tvocUcbCupA&hd=1) Commented Apr 22, 2014 at 12:54
  • I am trying to understand why you would want to use an arrow function this way at all. Is there a reason why you can't use a regular method on the prototype? Commented Apr 22, 2014 at 14:07
  • 2
    I prefer writing classes that assume this is the class, and handling scope and context using call, apply or an arrow function where calling code changes that context. Commented Apr 22, 2014 at 21:23
  • 1
    @web2nr This question stems from usage of #Angular, where some of the methods of my objects wind up being callbacks. Because the callback isn't obvious within my own code (I'm not using call in my own code), I found that the the context of this was not consistent. I thought I could simply use the arrow function everywhere in my classes and thus callbacks to my class would just work and from an Angular perspective it did. As I discovered though, this prevents me from using #Typescript inheritance. I think in practice I will have to be selective in my usage of arrow functions. Commented Apr 28, 2014 at 17:38
  • 2
    @RichardCollette I think this is a legitimate shortcoming of TypeScript that you have identified. It shouldn't provide classes unless this in a method is always the class instance. Callbacks are no excuse because they can and should be implemented with top-level functions. I have learned to live with using the fat arrow syntax, that is until I had the need to override methods. Bug filed, but I suspect it will be dismissed as "by design". typescript.codeplex.com/workitem/2491 Commented May 6, 2014 at 1:52

5 Answers 5

13

For the sake of argument, assume you

  • Are using the fat-arrow syntax because the methods are being triggered by UI events or callbacks (in my case knockout click events)
  • Need inheritance to eliminate redundancy in UI (or callback) respondent code.

A minimally hackish (if not elegant) answer is to split your function into two calls that address the two issues:

Class A {
    public handleScope = () => {
        return this.handleInheritance();
    }

    public handleInheritance() {
        // do work
    }
}

Class B extends A {
    public handleInheritance() {
         super.handleInheritance() // super works here
         // additional work
    }
}

I'm the first to admit that doubling functions is "ugly", but IMHO a lot less ugly than the other options I've seen. To help standardize naming, I'm naming the one-line "scoping" function the name of the base function (e.g. myFunction) plus "Scoper" (i.e. myFunctionScoper). This is also IDE-friendly because you'll often get the Scoper method as a hinted option when you start to type the name for the inheritable method.

Sign up to request clarification or add additional context in comments.

Comments

8

arrow functions properly or should they really only be used as a method of declaring something like a callback?

They should really only be used for callbacks. If you want a class hierarchy then use the prototype. prototype also saves you memory.

Forced fix: there is only one this and it is the current instance. If you overwrite this.foo in the child class the base instances this.foo is lost. Preserve the base version in the constructor

class BaseClass{

  count:number=0;

  public someMethod=():void =>{
      this.count++;
  }
}

class ChildClass extends BaseClass{

  constructor(){      
      super();
      var baseSomeMethod = this.someMethod;
      this.someMethod = ()=>{
          // implement here 
      }
  }

}

2 Comments

class Parent{ public foo=():void =>{ //stuff } } class Child extends Parent{ constructor(){ super(); var superFoo = this.foo; this.foo = ()=>{ superFoo(); } } }
I thought it would be helpful to add a barebones arrow function inheritance refactor of your code, with language in reference to parent and super. For those trying to draw that parallel it may be easier to see here.
1

Without a function implementation in the prototype, there's no way for the derived class to 'find' the base class implementation. You can separate it out so that you have one method for preserving this and another for using via super:

class BaseClass {
  count: number = 0;

  someMethodImpl() {
    this.count++;
  }

  public someMethod = this.someMethodImpl;
}

class ChildClass extends BaseClass {
  public someMethod = (): void=> {
    super.someMethodImpl();
    //Do more work here.
  }
}

Comments

0

Just would like to capture an "answer" to this question from another discussion here: https://typescript.codeplex.com/workitem/2491

Definitely not efficient in terms of memory or processing overhead but it does answer the question.

class Base {
    x = 0;
    constructor() {
        for (var p in this)
            if (!Object.prototype.hasOwnProperty.call(this, p) && typeof this[p] == 'function') {
                var method = this[p];
                this[p] = () => { method.apply(this, arguments); };
                // (make a prototype method bound to the instance)
            }
    }
}

class A extends Base {
    doSomething(value) { alert("A: " + value + " / x == " + this.x); }
}

class B extends A {
    doSomething(value) { alert("B: " + value + " / x == " + this.x ); super.doSomething(value); }
}

var b = new B();
var callback = b.doSomething;
callback("Cool!");

Comments

0

This works for me, and I think it's a little bit cleaner, because you only need to add one line in the derived class.

class Animal
{
    protected move = () =>
    {
        console.log('move')
    }
}

class Bird extends Animal
{
    private move_base = this.move;

    protected move = () =>
    {
        console.log('fly and ...')
        this.move_base();
    }
}

var bird = new Bird();
bird.move();

So how it practically works is that you just keep a reference to the original method before you overwrite it in the child class.

I just "discovered" this, so I haven't really battle tested it yet in a large project.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.