In TypeScript, the default type of this for methods within a class is the current instance of the class. However, when defining methods using arrow functions, the context of this is bound to the time of declaration, not when called.
Regular Method:
class Counter { value = 0; increment() { this.value++; } }
Arrow Function:
class Counter { value = 0; increment = () => { this.value++; } }
Nuances:
this context when passed as callbacks (for example, in event listeners).this in the method signature for additional checking:class Foo { bar(this: Foo) { // ... } }
What is the difference between
increment()andincrement = () => {}in a class? How does it affect thethiscontext when used as a callback?
Incorrect Answer:
Correct Answer:
this context is determined at the time of call. If you pass the method as a function: setTimeout(counter.increment, 0), this becomes undefined (in strict mode) or window (in non-strict), while the arrow function retains its environment:class Demo { value = 1; inc() { console.log(this.value); } incArrow = () => { console.log(this.value); } } const d = new Demo(); setTimeout(d.inc, 0); // undefined or error setTimeout(d.incArrow, 0); // 1
Story
In a project with reactive frameworks, class methods were passed directly as callbacks without an explicit bind. As a result, this became undefined, and the application crashed with an error when accessing this properties. The problem was resolved by rewriting methods to use arrow functions or by using explicit bind.
Story
A developer explicitly specified the type of this in the method but forgot about the typing inside the arrow function within that method. This resulted in this inside the nested callback pointing not to the instance of the class, but to window. The team faced a state leak and had to redo the event architecture.
Story
A large UI component was slowing down the application because all methods were described as arrow class fields (new Counter().increment = ...), which created new function copies for each instance instead of a single definition on the prototype, as with regular methods. Consequently, memory consumption increased, and optimization was needed.