How to handle the "this" pointer in TypeScript callbacks

Having a means of protecting you from the limitations and quirks of JavaScript is a pretty essential part of any modern JavaScript project and build chain. TypeScript is one of the best ways of doing this.

TypeScript offers us many great ways of ensuring that the "this" pointer is based on the context in which our functions are defined such as classes and arrow functions.

This is great in most situations but there are times when using callbacks we would want "this" to point to the context that the function is executing in.

Whilst the compiler is really smart at inferring the type of the "this" pointer, on occasion based on our actions, it will need a helping hand.

Ok so when is that ever going to happen?

There are 2 situations in my own experience where this happens often.

1. Event handlers

The first is if we are dealing with DOM events like a mouse click or text box change. In this case, we want (in many cases) the "this" type to refer to the element that our event is occurring on as this is what our code will refer to when referencing "this".

2. Testing

Another case where I saw this recently was when I was testing a Request Handler in Express.js using Mongoose.js to save data to MongoDb.

As I didn't want to actually hit the database in my test, I needed to replace the prototype's current implementation of the "save" method with a fake method (I had already made this a Sinon.js stub) that returned a Promise that resolved with the object itself. I.e. I wanted "this" to point to the instance of the object that I was attaching the method to, not the the current "this" object. (This was a test using Mocha so Mocha's testing context would be "this")

ProfileRecord.prototype.save.callsFake(function () {  
    let currentRecord = this;

    return Promise.resolve(currentRecord);
});

Now to be clear, the code itself at runtime would work fine but as I had the compiler setting of "strict" set to true then I need to help the compiler (and as a bonus, everyone else who works with the code, that's one of the main reasons to use the "strict" setting).

Currently, the editor would give us a nice red squiggly line like:
.

Manually setting "this" in TypeScript

However, TypeScript has a nice feature if you want to set the "this" pointer manually. In most cases, TypeScript can work "this" out but it is common in JavaScript testing to use the "require" function to get hold of a module's exports object directly and replace one of its value's. When we use the "require function" here we get the "any" type and in the test that I wrote, I was going to replace a function on this type's prototype. Fortunately, we can do this with relative ease:

ProfileRecord.prototype.save.callsFake(function (this: Profile) {  
    let currentRecord = this;

    return Promise.resolve(currentRecord);
});

We have simply added a type annotation for "this" as the first argument. At runtime, this will disappear. It's just to give the compiler a hand because of what we're trying to do and has the added benefits of letting everyone else on the team know what to do.

NB: One thing to note is that using an arrow function here will not work as it would result in code that would point "this" to the Mocha context object. But don't worry, if you do this the compiler will help you out by not compiling your code :).

Final thoughts

TypeScript isn't without its challenges or compromises. However, it does bring massive benefits to projects and most of the awkward situations that you might find yourself in have normally been worked out. This is one of the benefits we are now seeing due to the maturity and increasing power of TypeScript's typing system.

Andrew de Rozario

Self / community educated developer who loves all things web, JavaScript and .Net related. Passionate about sharing knowledge, teaching and eating though maybe not in that order.

Subscribe to Just In Time Coder

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!