Typescript mis-reference to _this
Asked Answered
B

1

6

I tried to define some property for String.Prototype in TypeScript:

Object.defineProperty(String.prototype, 'test', {
    value: () => {
        console.log("this is a test over text " + this);
    }
})

in javaScript prototypes, this refers to the object which called the method (in this case the string value). But compiled output of the file is:

var _this = this;
Object.defineProperty(String.prototype, 'test', {
    value: function () {
        console.log("this is a test over text " + _this);
    }
});

TypeScript compiler adds variable _this and refers to it.

Is that a bug or there is a problem in my implementation?

Bradford answered 18/10, 2015 at 11:37 Comment(3)
Shouldn't the last value of Object.defineProperty be a descriptor Object?Berget
@nils: Yes, it should.Daisy
Be careful around this and arrow functions in TypeScript / ES6 / JavaScript : basarat.gitbooks.io/typescript/content/docs/… see Arrow Function DangerBarberabarberry
D
13

Is that a bug or there is a problem in my implementation?

No, it's how TypeScript's arrow functions work: In arrow functions, this is inherited from the context in which the function is created, rather than being set by how it's called. (Arrow functions are also in ES2015, inspired at least in part by CoffeeScript's "fat arrow" functions; I don't know the history of TypeScript and whether it was also part of the inspiration for ES2015's arrow functions or vice-versa.)

Here's a quote from the spec link above:

A function expression introduces a new dynamically bound this, whereas an arrow function expression preserves the this of its enclosing context.

Arrow function expressions are particularly useful for writing callbacks, which otherwise often have an undefined or unexpected this.

In the example

class Messenger {  
    message = "Hello World";  
    start() {  
        setTimeout(() => alert(this.message), 3000);  
    }  
};

var messenger = new Messenger();  
messenger.start();

the use of an arrow function expression causes the callback to have the same this as the surrounding 'start' method.

If you want this to depend on how the function was called, don't use an arrow function, use function:

Object.defineProperty(String.prototype, 'test', function() {
    console.log("this is a test over text " + this);
})

Also note that as nils points out the third argument to Object.defineProperty should be a property descriptor, not a function. You may have meant:

Object.defineProperty(String.prototype, 'test', {
    value: function() {
        console.log("this is a test over text " + this);
    }
});

The TypeScript transpiler doesn't change that at all; calling "testing".test() outputs "this is a test of text testing":

Object.defineProperty(String.prototype, 'test', {
    value: function() {
        snippet.log("this is a test over text " + this);
    }
});
"testing".test();
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Daisy answered 18/10, 2015 at 11:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.