Koshmaar
Koshmaar

Reputation: 166

strange method definition in Typescript class

I'm following along this heroku tutorial and in this section https://devcenter.heroku.com/articles/mean-apps-restful-api#create-the-contact-list-template-and-component there is class listing of ContactListComponent

There's function

  private getIndexOfContact = ( contactId : String ) => {
    return this.contacts.findIndex( (contact) => { return contact._id === contactId; } );
  }

that is used like that:

deleteContact = (contactId: String) => {
var idx = this.getIndexOfContact(contactId);
if (idx !== -1) {
  this.contacts.splice(idx, 1);
  this.selectContact(null);
}
return this.contacts;

}

Why is the getIndexOfContact implemented like that, instead of ie:

  private getIndexOfContact( contactId : String )
  {
    return this.contacts.findIndex( (contact) => { return contact._id === contactId; } );
  }

What is this syntax changing?

Upvotes: 0

Views: 72

Answers (2)

Nitzan Tomer
Nitzan Tomer

Reputation: 164177

They are using an arrow function which handles the context of this better than a regular function.

Example:

class A {
      fn1() {
            console.log(this);
      }

      fn2 = () => {
            console.log(this);
      }
}

let a = new A();
setTimeout(a.fn1, 10); // Window
setTimeout(a.fn2, 10); // A {}

(code in playground)

Another difference between the two is that when using arrow functions as class methods, you don't really get a method but a property on the instance of type function.
That means that the function won't be added to the prototype and won't be added to subclasses.

The compiled js of my example is:

var A = (function () {
    function A() {
        var _this = this;
        this.fn2 = function () {
            console.log(_this);
        };
    }
    A.prototype.fn1 = function () {
        console.log(this);
    };
    return A;
}());

As you can see fn1 is assigned to the prototype while fn2 is assigned to the instance in the constructor.


Edit

A lot of people will say that using arrow functions as class methods is good practice because it keeps the context of this for the function, but they are rarely talking about the downsides, so here it is:

class B extends A {
      fn1() {
            console.log("B.fn1");
            super.fn1();
      }

      fn2 = () => {
            console.log("B.fn2");
            super.fn2(); // error: Only public and protected methods of the base class are accessible via the 'super' keyword
      }
}

There's a way around that of course:

class B extends A {
      private oldFn2 = this.fn2;

      constructor() {
            super();      
      }

      fn1() {
            console.log("B.fn1");
            super.fn1();
      }

      fn2 = () => {
            console.log("B.fn2");
            this.oldFn2();
      }
}

But that's way too much work to be able to call super.

Upvotes: 0

Marc Hägele
Marc Hägele

Reputation: 342

The syntax changing is a recommended solution to avoid getting issues when using "this" keyword calling per example the declared function as a callback function.

I had a lot of trouble using the "normal" style way, and after using always the solution " = () => { ..." in my projects the problems were gone.

Upvotes: 2

Related Questions