Introduction to TypeScript Functions — This Object and Overloads
Tags: webdev, programming, typescript, javascript
Published: 2021-01-23 19:58:47

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

Functions are small blocks of code that take an input and either return an output or have side effects, which means that `if` modifies variables outside the function. We need functions to organize code into small blocks that are reusable. Without functions, if we want to re-run a piece of code, we have to copy it to different places. Functions are critical to any TypeScript program. In this part of the series, we continue to look at different parts of TypeScript functions, including how to deal with the `this` object with TypeScript, and overloading functions.

* * *

This Object
===========

If `this` is referenced in the regular function declared with the `function` keyword, the `this` object isn’t set inside an arrow function to the function that has the `this` inside. If an arrow function is inside a constructor, then `this` is set to the new object. If it’s not inside an object, then `this` inside the arrow function is `undefined` in strict mode. `this` will be set to the base object if the arrow function is inside an object. However, we always get the `window` object if we reference `this` in an arrow function. For example, the following code wouldn’t compile and run since TypeScript doesn’t allow our code to have the global variable as the value for `this`:

```
const fn = () => this  
console.log(fn());
```

We get the `window` object logged when `console.log` is run. Likewise, if we ran this:

```
let obj = {}  
obj.f = () => {  
  return this;  
};  
console.log(obj.f());
```

We get the same thing as we got before. This is in contrast to the traditional functions declared with the `function` keyword. Let’s see what happens if we replace the functions above with traditional functions in the code above, as in the following code:

```
const fn = function() {  
  return this  
};  
console.log(fn);
```

Now, if we have `noImplicitThis` flag on in our `tsconfig.json`, we get the following error from the TypeScript compiler: `'this' implicitly has type ‘any’ because it does not have a type annotation.(2683)`

We’re closer to getting our code working, but it’s still not going to compile. To fix this error, we need to put a fake parameter, `this: void`, in the function signature, as in the code below:

```
const fn = function(this: void) {  
    return this;  
};  
console.log(fn);
```

With the code above, we make the `this` variable unusable. If we want to use it for something, we can add an explicit type for `this` instead of `void`, to make it do something. For example, if we want to make a constructor object, we can write something like the following code:

In the code above, we created an interface called `Person` to add a data type to the `this` object in the `greet` function in the `person` object. When we call the `greet` function, the `this` parameter is ignored since we placed it as the first parameter. TypeScript only looks at the type of `this` in the parameter and will not expect us to call the `greet` function by passing in an argument for `this`. After defining the `person` object, we can then assign values to the `name` and `age` properties outside it. We already met the requirements listed in the interface when we’re defining the `person` object, but we should also assign some meaning value to it so we can use the `greet` function.

Then, when we run we run the `console.log` in the last line of the example above, we get `Hi Jane. You’re 20 years old`. We’ve successfully created a data type for `this`, so there won’t be any ambiguity as to what the value of `this` is. This helps developers understand what `this` has in the code since this is one of the more confusing aspects of JavaScript. In plain JavaScript, `this` can take on different values depending on where the `this` keyword is located in the code. In traditional functions, `this`’s value would be the function itself. Arrow functions do not change the value of `this`, so whatever it was outside is the same as whatever it is inside the arrow function.

With TypeScript, we can’t use the `this` and traditional functions to create classes. For example, if we write:

Then we would get the error `Cannot find name ‘Person’. Did you mean ‘person’?(2552)` and the code won’t compile. TypeScript doesn’t let us use traditional functions as classes. To use make classes, we must use the `class` syntax.

* * *

‘this’ Parameters in Callbacks
==============================

For callback functions used for event listeners, the callback functions that we pass in should be typed in an interface. For example, for setting the type of custom input control components, we can write something like Tthis:

```
interface InputElement {  
  addKeyUpListener(onclick: (this: void, e: Event) => void): void;  
}
```

Then, when people that use the control, then they can write something like this for it to run:

What if developers that use the library try to reference `this`, as in the following code?:

In this case, the TypeScript compiler will throw an error since `this` is marked with the `void` type in the `InputElement` interface.

* * *

Function Overloads
==================

Overloading a function is creating functions with the same name, but with different signatures. This isn’t allowed in JavaScript since functions are objects and we can’t re-declare the same object multiple times. However, since TypeScript is strongly typed, which is the opposite of the dynamic nature of JavaScript, it has to find a way to accommodate the dynamic aspects of JavaScript. To do this, TypeScript provides us a way to overload functions with different signatures. To overload functions with TypeScript, we just have to write multiple function signatures with the same name before defining the actual function with that name. For example, we can write something like this:

```
function getPerson(person: { name: string, age: number }): { name: string, age: number };  
function getPerson(person: { name: string }): { name: string };  
function getPerson(person: any): any {  
  return person;  
}
```

With the code above, we have a `getPerson` function that can either accept an object with the properties `name` and `age` , or just the property `name`. The return type, which is after the colon, can either be an object with both the `name` and `age` properties, or an object with just the `name` property. This is what we have in the first three lines of the code example above, where we just define the signatures we want for our `getPerson` function.

Then in the actual `getPerson` function definition, we have the actual function definition. We annotate the type of the parameter and return as `any` , which is OK because we already defined the parameters and return types that the `getPerson` accepts and returns respectively. We can call the `getPerson`, as in the code below:

```
console.log(getPerson({ name: 'Jane', age: 20 }));  
console.log(getPerson({ name: 'Jane' }));
```

From the `console.log` statements above, we get:

```
{name: "Jane", age: 20}  
{name: "Jane"}
```

If we try to call it with an argument that we didn’t define in the signature like: `console.log(getPerson({}))` we get a `No overload matches this call` error.

The main way to deal with the `this` object in traditional functions is to pass it in as the first parameter of a function and then set a type to it by defining an interface for the type. TypeScript will ignore the `this` parameter and treat it as if it doesn’t exist. It’s only used for setting the data type of `this`. We can overload functions in TypeScript, which isn’t allowed in JavaScript. To do this, we just define different signatures for the function and give them the same name, then define the function with the same name after we defined the signatures that our function will accept.