TypeScript, event handlers in the DOM, and the this keyword
Tags: javascript, typescript, webdev
Published: 2020-01-02 11:24:57

---
title: "TypeScript, event handlers in the DOM, and the this keyword"
published: true
description: "In this quick post you'll learn how to make TypeScript play well with the infamous this keyword when working with event handlers in the DOM."
tags: javascript, typescript, webdev
canonical_url: https://www.valentinog.com/blog/this/
---

_In this quick post you'll learn how to make TypeScript play well with the infamous this keyword when working with event handlers in the DOM._

## What is this in JavaScript?

**this** in JavaScript is a magic keyword for: “whichever object a given function runs in”. Consider the following object and its nested function:

```js
const person = {
  name: "Jule",
  printName: function() {
    console.log(this.name);
  }
};
```

When I call person.printName(), this will point to the person object. this is everywhere in JavaScript and depending on the skill level developers simply decide to avoid it in fear of errors or embrace it 100%. I’m on the second group.

**this** is also convenient when working with event handlers in the DOM and you’ll see why in a minute.

## What are event handlers in JavaScript?

The Document Object Model is a convenient representation of every element in an HTML page. Browsers keep this structure in memory and expose a lot of methods for interacting with the DOM.

HTML elements in the DOM are not static. They are connected to a primordial object named **EventTarget** which lends them three methods:

- addEventListener
- removeEventListener
- dispatchEvent

Whenever an HTML element is clicked, the most simple case, an **event is dispatched**. Developers can intercept these events (JavaScript engines are event-driven) with an **event listener**.

Event listeners in the DOM have access to this because the function runs in the context object who fired up the event (an HTML element most of the times). Consider the following snippet:

```js
const button = document.querySelector("button");
button.addEventListener("click", handleClick);

function handleClick() {
    console.log("Clicked!");
    this.removeEventListener("click", handleClick);
}
```

Here removeEventListener is called on the HTML button who triggered the click event. Now let’s see what happens when we **convert this code to TypeScript**.

## TypeScript and this

When converting our code to TypeScript the IDE and the compiler will complain with two errors:

```typescript
error TS2531: Object is possibly 'null'.
error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
```

We can get rid of the first error with optional chaining, landed in TypeScript > 3.7:

```typescript
const button = document.querySelector("button");
// optional chaining
button?.addEventListener("click", handleClick);

function handleClick() {
    console.log("Clicked!");
    this.removeEventListener("click", handleClick);
}
```

For the second error to go away instead, **this must appear as the first parameter in the handler signature, with the appropriate type annotation**. HTMLElement is enough in this case:

```typescript
const button = document.querySelector("button");
button?.addEventListener("click", handleClick);

function handleClick(this: HTMLElement) {
    console.log("Clicked!");
    this.removeEventListener("click", handleClick);
}

```

You might have guessed how the “trick” is applicable to any function dealing with **this**, not necessarily an event handler (don’t mind any here, it’s bad):

```typescript
function aGenericFunction(this: any, key: string) {
  return this.doStuff(key);
}

const aFictionalObject = {
  first: "a",
  second: "b",
  doStuff: function(str: string) {
    return `${this.first} ${str}`;
  }
};

aGenericFunction.call(aFictionalObject, "appendMe");
```

Originally published on [my blog](https://www.valentinog.com/blog/this/)