Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Visual Studio shows wrong value for `this` in TypeScript [duplicate]

Consider following code:

class Person{
    firstname = ko.observable<string>();
    lastname: ko.observable<string>();
    fullname = ko.computed(()=>{

        // Breakpoint here
        return this.firstname() + ' ' + this.lastname();

    });

when I'm debugging with Visual Studio 2013, if I put a breakpoint and see the value of this using watch or immediate window, it shows that the value is window not the person instance. Consequently, it shows undefined for this.firstname.

Checking the converted JavaScript code I find out that I should check the value of _this instead of this.

Although code runs without an error, but it waste lots of my time to understand that the true value of this variable is available through _this.

Question Am I somewhere wrong in using the class properties which causes this misleading value in this value? or it's just a bug? or maybe it's by design for some reason?

like image 811
mehrandvd Avatar asked May 05 '15 15:05

mehrandvd


2 Answers

Due to how the "this" keyword works in javascript Typescript creates the "_this" alias for you. This is by design, and is great when you know how it works.

Your example:

class Person {
    firstname = ko.observable<string>();
    lastname: ko.observable<string>();
    fullname = ko.computed(
        () => {
            // Breakpoint here
            return this.firstname() + ' ' + this.lastname();
    });
}

Compiles to:

var Person = (function () {
    function Person() {
        var _this = this;
        this.firstname = ko.observable();
        this.lastname = ();
        this.fullname = ko.computed(function () {
            // Breakpoint here
            return _this.firstname() + ' ' + _this.lastname();
        });
    }
    return Person;
})();

This shows (as you mentioned) that "this" in your fullname computed function has been compiled to "_this". Your issue with the debugging is that Visual Studio is debugging the compiled javascript. And in javascript "this" inside the function means something else, read more about "this" in javascript here.

Typescript creates a _this reference when you use a lambda function, i.e:

class foo {

    something: string = "some string";

    foo1 = () => { this.something }
    foo2() { this.something }
}

Compiles to:

var foo = (function () {
    function foo() {
        var _this = this;
        this.something = "some string";
        this.foo1 = function () { _this.something; };
    }
    foo.prototype.foo2 = function () { this.something; };
    return foo;
})();

If used correctly lambda functions in typescript solves the "this" hell from javascript. In most cases you do not need to think about when to use lambdas or functions, but in some cases you do. More information about lambda functions can be found here.

The short answer for working with this is to inspect _this when working with lambdas until it is fixed. There is an open issue for it: https://typescript.codeplex.com/workitem/1655.

like image 127
Nypan Avatar answered Nov 04 '22 09:11

Nypan


Well, you just stumbled on one of the hassle of JavaScript. "this is driving me crazy, but I have no idea what this is referring to". So this is not a bug, this is by design. Long story short, JavaScript rescopes this according to the context. This is particularly problematic when using libraries such as d3 (for events callbacks) or angular, or knockout in your case. This problem becomes inherintly more obvious when using TypeScript because you have to use this everywhere. You can find more documentation about the use of this on the mozilla developer network.

To circumvent your problem, the easiest solution is to keep a reference to the original this before entering your callback, and use the local variable inside, i.e.:

class Person{
  firstname = ko.observable<string>();
  lastname: ko.observable<string>();
  var self = this;
  fullname = ko.computed(()=>{

    // Breakpoint here
    return self.firstname() + ' ' + self.lastname();

  });

This is an habit I suggest you adopt to avoid future problems, and is kind of a good practice in JavaScript.

like image 34
Hugues Stefanski Avatar answered Nov 04 '22 09:11

Hugues Stefanski