TypeScript: Wrong 'this' context in class methods
Currently, the type system included in TypeScript does not allow proper typing of the this context. There are attempts to fix that (See #3694 for example), but these will take a while to ripe and until then I would like to suggest a “quick fix” for class methods, because the following pitfall appears often when interacting with web-libraries. Consider the following code:
class Foo {
private bar: string = "Bar";
logBar(): void {
console.log("Bar's value is: " + this.bar);
}
}
// many javascript frameworks rebind the this context for callbacks,
// see for example jQuery's $("foo").click or React's onClick
function fireCallback(cb: (() => any)): void {
let someObj = {
hello: "42"
};
cb.call(someObj);
}
let x = new Foo();
fireCallback(x.logBar);
This code typechecks perfectly:
$ tsc --version
message TS6029: Version 1.5.0-beta
$ tsc --noImplicitAny main.ts
But does not produce the desired result:
$ node main.js
Bar's value is: undefined
Many libraries rebind the this context for callbacks, so my suggestion would be that the tsc transforms methods passed as arguments by wrapping them in an anonymous function like so:
fireCallback((...args: any[]) => x.logBar.call(x, args));
This should be okay, be cause inside a method the compiler assumes that this
is of the classes type so there’s no way to interact with later bound this objects anyhow.
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Comments: 16 (6 by maintainers)
@kitsonk Hm, if that example is valid TypeScript I find that odd… Wouldn’t that mean that
x
have different types before and afterx.logBar = undefined
?@RyanCavanaugh While I don’t know too much about the ES6 Spec, I found 4.3.31 method stating:
I agree that my first proposal is very hacky, so we came up with another solution together with @skogsbaer : How about compiling class methods to something like this:
That way the typing of
this
is correct inside a class method.this
in your class method due to the type checker? (Inside the methodthis
has the type of the class?)x.logBar
can not benull
orundefined
iffx.logBar
is a class method ofx
? I would expect the type system to catch this if this is possiblethis
is practice.For this issue, I would suggest binding the method to “this” in the constructor. This works “this.showMessage = this.showMessage.bind(this);” .
Some nice info about it here: https://daveceddia.com/avoid-bind-when-passing-props/
@RyanCavanaugh So what’s a proposed practice to overcome the issue?