Ryan McClure
Ryan McClure

Reputation: 1223

'this' type inferred as 'any' in Typescript class prototype method

Say I have a class with a _type property and getType method:

class Thing {
  _type: number;

  getType: () => number;
}

I then want to define the getType method outside of the class:

Thing.prototype.getType = function getType() {
  return this._type;
}

In the getType definition, this is getting inferred as any, rather than the type of Thing. However, if getType is defined inside the class definition it works just fine.

What is wrong with this? Is there some syntax that needs to be used to bind this to the function definition?

Upvotes: 1

Views: 264

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249796

Methods declared in the class will have this types as an instance of the class (although there is no guarantee this will actually be an instance of the type at runtime).

Functions defined and assigned to the prototype will o benefit from any inference for this, since the method signature does not actually preserve the type of this.

class Thing {
    getType() { }
}

let fn = Thing.prototype.getType // fn has type ()=> void instead of (this: Thing) => 

There was a discussion to better type this, but it's performance implications were prohibitive (10-20% perf impact on class heavy code, if I remember correctly) so it was scrapped. Although the example above makes it seem trivial, typing this is not easy when you take into account derived classes, as this would have to essentially be a type parameter, which causes the slow down.

You can use an explicit annotation for this (the extra parameter will be erased during compilation):

Thing.prototype.getType = function getType(this: Thing) {
  return this._type;
}

Playground Link

Or, if as in your case, the method is actually declared as a field on the class, you can add the annotation for this on the field signature, and benefit from the annotation when you assign it:

class Thing {
  _type!: number;
  getType!: (this: Thing) => number;
}


Thing.prototype.getType = function getType() {
  return this._type;
}

Playground Link

Upvotes: 3

Related Questions