TypeScript, although very promising language, does not solve fundamental JavaScript's issue (feature?) with "this" property binding. TypeScript can lead to unfortunate errors since it is heavily used by people coming from C#/Java communities, who bring coding patterns with them. Let's have a look at code example from TypeScript playground:
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("Alexander");
console.log(greeter.greet()); // Hello, Alexander
Now, lets make slight change to the last two code lines:
let greeter = new Greeter("Alexander").greet;
console.log(greeter()); // Hello, undefined
This happens because greet()
method references this
and when you make a call of greet()
not on the object, this
gets bound to the global scope. It's really unfortunate that one can so easily destroy TypeScript object's integrity. In C# this example would work just fine and therefore C# developers should be extra careful to avoid this pitfall:
using System;
public class Program
{
class Greeter {
string greeting;
public Greeter(string message){
this.greeting = message;
}
public string greet(){
return "Hello, " + this.greeting;
}
}
public static void Main()
{
Func<string> greeter = new Greeter("Alexander").greet;
Console.WriteLine(greeter()); // Hello, Alexander
}
}
Now, even knowing all rules of this
binding (take a look at this article if you are not aware of these rules), I was caught when I was coding in TypeScript class for Angular 2 framework:
export class Timer {
@Output() onFinished = new EventEmitter();
@Input() duration;
start() {
updateClock();
var timeinterval = setInterval(updateClock, 1000);
function updateClock() {
this.duration = this.duration - 1;
if (this.duration <= 0) {
clearInterval(timeinterval);
this.onFinished.emit({});
}
}
}
}
See how updateClock
local function starts accessing Timer
properties via this
? Seriously, I was debugging this code full of surprise trying to understand why am I getting an error. And the reason was that updateClock()
is invoked without binding to any object which meant binding to the global scope again.
Conclusion: TypeScript is great, but guys, don't relax, remember you are still coding in JavaScript, not C# or Java. And probably avoid using classes and this
altogether.