Typescript: BUG: Undefined - due to inconsistent use of a class' _this when using different method syntaxes

Created on 29 Apr 2017  路  4Comments  路  Source: microsoft/TypeScript



TypeScript Version: whichever version is currently running in TypeScript Playground (2.3 I think)

Code

class MyClass {
    property: string = "Hello";

    print1 = () => console.log("print1, this.property = ", this.property);

    print2 = function() {
        console.log("print2, this.property = ", this.property);
    }

    print3() {
        console.log("print3, this.property = ", this.property);
    }
}

let myClass = new MyClass();
let lambda: () => void;

lambda = myClass.print1;
lambda();

lambda = myClass.print2;
lambda();

lambda = myClass.print3;
lambda();

Expected behavior:
_(Console Output)_

print1, this.property = Hello
print2, this.property = Hello
print3, this.property = Hello

Actual behavior:
_(Console Output)_

print1, this.property = Hello
print2, this.property = undefined
print3, this.property = undefined

Comments
While print1 (the method that was defined in MyClass as an 'expression bodied member') works as expected, the other two syntaxes result in what appears to be buggy behaviour.

I looked into why this was the case. See below for the transcompiled javascript for defining MyClass.

var MyClass = (function () {
    function MyClass() {
        var _this = this;
        this.property = "Hello";
        this.print1 = function () {
            return console.log("print1, this.property = ", _this.property);
        };
        this.print2 = function () {
            console.log("print2, this.property = ", this.property);
        };
    }
    MyClass.prototype.print3 = function () {
        console.log("print3, this.property = ", this.property);
    };
    return MyClass;
}());

The problem is related to use of the keyword 'this', which obviously varies based on the calling context.

You can see an attempt to solve the issue by storing a '_this' variable to capture the MyClass context. However '_this' is only dereferenced by print1, while print2 and print3 utilize the 'this' keyword directly.

When called normally (not by assigning the function to a variable and invoking) 'this' refers to MyClass. However, when called through a lambda variable, 'this' ends up referring to the global Window object. This was the context at the time of lambda initialisation.

It seems that this inconsistent behaviour could be avoided through use of a '_this' variable in the transcompiled javascript, as has been used in print1.

Working as Intended

Most helpful comment

This is expected and proper behavior. Only the print1 = () => syntax can be called like that without .bind()ing.

All 4 comments

This is expected and proper behavior. Only the print1 = () => syntax can be called like that without .bind()ing.

Thanks for the response. But why is this accepted as proper behaviour? What benefit is provided that offsets the confusion of having an apparently normal syntax for instance methods, but which result in not actually refering to the class instance?

Unfortunately this behavior is from Javascript. Since all JS is valid TS, TS needs to follow that behavior. In JS, 'this' is determined in how you __call__ a function and () => is a newer syntax (and semantics) that does not have that 'problem'.

Cool, thanks for explaining why the fat arrow syntax behaves differently to the others

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wmaurer picture wmaurer  路  3Comments

siddjain picture siddjain  路  3Comments

bgrieder picture bgrieder  路  3Comments

dlaberge picture dlaberge  路  3Comments

remojansen picture remojansen  路  3Comments