Progressively Typing a Function in TypeScript
Tags: typescript, javascript
Published: 2019-05-06 11:57:00

---
title: Progressively Typing a Function in TypeScript
published: true
description: In this article I’ll show you how to gain more confidence in your code by progressively adding Types to your functions.
canonical_url: https://www.inextenso.dev/progressively-typing-a-function-in-typescript
tags: TypeScript, JS
---

When I started with TypeScript I’ve found very easy and intuitive the whole type system for the majority of the things that I wanted to accomplished.

It was a good feeling. Finally I was able to have some confidence that my code would not break at runtime and the clever Intellisense in the IDE was helping my productivity.

What does it feel like then?

Take a look at this little snippet of code.

```typescript
class Hello {
    myMessage: string;
    constructor (message: string) {
        this.myMessage = message;
    }
    sayHello() {
        return "Hello, " + this.myMessage;
    }
}
```

Referencing the Hello Class in your code will produce hints and useful error messages if the correct type is not passed in the constructor.

![TypeScript Playground](https://www.inextenso.dev/Files/_playground.png)
Of course all the good things come to an end.

When I started to add typings to more complicated code bases I quickly realised that I had to be smarter with my types. If I wanted to truly take advantage of the type system I would have to dig deeper and find better patterns.

I struggled the most with functions.

In this article I’ll try to demonstrate an incremental pattern that helped me to understand better some concepts in TypeScript.

### Scenario: `safeDelete()`

We’ve been requested to write a function that takes 2 parameters: an `Object` and a `key`.

What this function should do is to delete the given key and return a copy of the new Object. If the key is not in the Object it should return undefined.

## Plain JS version

```javascript
function safeDelete(obj, key) {
    if (obj.hasOwnProperty(key)) {
        const shallowCopy = {...obj}
        delete shallowCopy[key];
        return shallowCopy;
    }
    return undefined;
}

// Calling the function
safeDelete({ a: 1, b: 2 }, 'b'); // {a: 1}
```

Let’s add some types to it, shall we?

## TypeScript version (Step 1)

```typescript
function safeDelete(obj: any, key: string) {
    if (obj.hasOwnProperty(key)) {
        const shallowCopy = {...obj}
        delete shallowCopy[key];
        return shallowCopy;
    }
    return undefined;
}
```

Simple enough right?

The problem with this approach is that the inferred return type is `any`

```typescript
function safeDelete(obj: any, key: string): any
```

Let’s improve it!

##TypeScript version (Step 2)

Let’s try to add a better type signature to our function

```typescript
type objDelete = (obj: object, key: string) => object | undefined;

const safeDelete: objDelete = (obj, key) => {
      if (obj.hasOwnProperty(key)) {
        const shallowCopy = {...obj}
        delete shallowCopy[key as keyof typeof obj];
        return shallowCopy;
    }
    return undefined;
}
```

What we’re saying here is that our function will take only an object and a string as parameters and will return either undefined or an Object

The inferred return type will be: 

```typescript
const safeDelete: (obj: object, key: string) => object | undefined
```

## TypeScript version (Step 3)

```typescript
function safeDelete<T>(obj: T, key: string) {
    if (obj.hasOwnProperty(key)) {
        const shallowCopy = {...obj}
        delete shallowCopy[key as keyof typeof obj];
        return shallowCopy;
    }
    return undefined;
}
```

The inferred return type will be: 

```typescript
function safeDelete<{ a: number; b: number; }>(obj: { a: number; b: number; }, key: string): { a: number; b: number; } | undefined
```

Much better now! 👍

Using TypeScript Generics will allow us to create a component that can work over a variety of types rather than a single one.

The compile is super smart and will do the work for us.

You can now safely operate on the return value of the function.

As you can see you can progressively making your type signature smarter.