TypeScript - how to inherit class and override lambda method

18,472

Solution 1

Well, you can't have that.
There's an issue that was opened but it was closed as "by design".

You should use regular methods:

class Base {
    protected prop = null;

    constructor() {
        this.init();
        this.initLambda();
    }

    init() {
        console.log("Base init");
    }

    initLambda() {
        console.log("Base initLambda");
    }
}

class Derived extends Base {
    constructor() {
        super();
    }

    init() {
        console.log("Derived init");
    }

    initLambda() {
        console.log("Derived initLambda");
    }
}

And then it will work.

As for keeping the right this, you can always pass a call to the method as an arrow function:

doit() {
    setTimeout(() => this.init(), 1);
}

Or use the Function.prototype.bind function:

setTimeout(this.init.bind(this));

Also, the _this thing that the typescript compiler produces is just a hack to polyfil the arrow functions for ES5, but if you change the target to ES6 then it won't use it.


Edit:

You can save the bound methods as members:

class Base {
    ...
    public boundInit: () => void;

    constructor() {
        ...
        this.boundInit = this.initLambda.bind(this);
        setTimeout(this.boundInit, 500);
    }

...

With that, when I do new Derived() this is what I get:

Derived init
Derived initLambda // after 200 millis

Solution 2

The problem is that your lambda is a property.

When compiled to javascript, the Baseclass becomes

var Base = (function () {
    function Base() {
        this.prop = null;
        this.initLambda = function () {
            console.log("Base initLambda");
        };
        this.init();
        this.initLambda();
    }
    Base.prototype.init = function () {
        console.log("Base init");
    };
    return Base;
}());

As you can see initLambda is defined inside the constructor of Base, so there is no way you can override that.

Calling super() calls the Base constructor which defines the this.initLambda with the code in Base and runs it. Hence your result.

View on playground

Share:
18,472
user210757
Author by

user210757

Updated on July 18, 2022

Comments

  • user210757
    user210757 almost 2 years

    I have an inherited class, and need the parent to have a virtual method, which is overridden in the child class. This method is called from the base constructor, and needs access to instance properties, so it needs to be a lambda function, so "this" is "_this". The problem is, overriding a lambda method does not work for me like overriding a non-lambda does. Is this possible? If not, I'd like to understand why.

    Also, will "this" always be the same as "_this" when the method is only called from the constructor?

    class Base {
        protected prop = null;
        constructor() {
            this.init();
            this.initLambda();
        }
        init() {
            console.log("Base init");
        }
        initLambda = () => {
            console.log("Base initLambda");
        }
    }
    class Derived extends Base {
        constructor() {
            super();
        }
        init() {
            console.log("Derived init");
        }
        initLambda = () => {
            //let x = this.prop;
            console.log("Derived initLambda");
        }
    }
    

    Output:
    Derived init
    Base initLambda

  • user210757
    user210757 almost 8 years
    I guess you could say you CAN override it, but it's not overridden until instantiated.
  • Bruno Grieder
    Bruno Grieder almost 8 years
    @user210757 yes. Basically, don't call this.initLambda() in the Base constructor, override it in Derived then call it from Derived
  • user210757
    user210757 almost 8 years
    Along these lines, I thought this might work in the base constructor but did not - let x = () => this.initLambda(); x();
  • Nitzan Tomer
    Nitzan Tomer almost 8 years
    You can save bound functions like that as members and then use those. What do you by "not working"?
  • user210757
    user210757 almost 8 years
    Did not call the derived method - that is what I was trying to do.
  • Nitzan Tomer
    Nitzan Tomer almost 8 years
    Check my revised answer
  • benshabatnoam
    benshabatnoam over 5 years
    'There's an issue that was opened but it was closed as "by design".' - the link is broken
  • Nitzan Tomer
    Nitzan Tomer over 5 years
    @benshabatnoam right, well, this post is pretty old... I have no idea if they recreated this issue (or what it was) in github.