Notes on TypeScript: ReturnType
Tags: typescript, types
Published: 2019-01-27 15:59:53

---
title: Notes on TypeScript: ReturnType
published: true
description: Better understanding ReturnType
tags: typescript, types
series: Notes on TypeScript
---


### Introduction

These notes should help in better understanding `TypeScript` and might be helpful when needing to lookup up how leverage TypeScript in a specific situation. All examples are based on TypeScript 3.2.

### ReturnType

In the following we will talk about the `ReturnType`.
To better understand `ReturnType`, we will build examples a long the way, that should display where using this conditional type might be useful.

Before we go into more depth, let's write a basic example to demonstrate how `ReturnType` functions.
We have a `getInt` function that expects an input of type `string` and parses the integer value of given input.

```js
function getInt(a: string) {
  return parseInt(a);
}

type A = ReturnType<typeof getInt>; // => number
```

Using `typeof`, we are able to able to get hold of the type signature of `getInt`, which in this case would mean `(a: string) => number`. `ReturnType` accepts a function and returns the return type that the function would return when being invoked. `number` in our `getInt` example.

Taking this approach has one main advantage, we don't need to keep the return types in sync with our function definition.

### Advanced

Now that we have seen what `ReturnType` does and how we can leverage this type in it's most basic form, let's try to get a deeper understanding and see more advanced cases.

```js
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
```

Above, is the `ReturnType` implementation. It tries to infer the return value and either returns the inferred type or `any`.

In our next example, we want to get a hold of the return type of a function that creates a `User`.

```js
let id = 0;
function createUser(name: string, position: string) {
  return {
    id: id++,
    name,
    position,
    createdAt: new Date()
  };
}

type User = ReturnType<typeof createUser>;
// => {id: number, name: string, position: string, createdAt: Date}
```

Again, `ReturnTypes` can return the created `User` type. This means we don't have to keep our types in sync with our function declaration.
Here are more examples using `ReturnType`.

```js
type A = ReturnType<any>; // => any
type B = ReturnType<never>; // => never
type C = ReturnType<() => string>; //=> string
```

Our next example is trying to infer the `None` type, where we define a constant for `None`.

```js
const None = "None";

function none() {
  return {type: None}
}

type NoneType = ReturnType<typeof none>; // => {type: string}
```

Interestingly type `NoneType` is defined as `{type: string}` but should actually be `{type: "None"}`.
To enable TypeScript to infer the correct type, we need to be explicit about the `None` constant in this case.

```js
const None = "None";

function none() {
  return {type: None as typeof None}
}

type NoneType = ReturnType<typeof none>; // => {type: "None"}
```

By explicitly defining the `None` type, `ReturnType` can infer the correct type.
We need to keep this in mind in these specific cases.

Finally, let's see how we might be able to infer the return type of a generic function.

```js
function identity<T>(a: T) : T {
  return a;
}
```

Let's see what `ReturnType` can infer:

```js
type IdentityType = ReturnType<typeof identity>; // => {}
type IdentityType = ReturnType<typeof identity<number>>; // => syntax error!
```

So we can't infer identity.
How do we infer the return type of a generic function then?

We need to implement our own return type as suggested [here](https://stackoverflow.com/a/50321754).

```js
interface Callable<ReturnType> {
  (...args: any[]): ReturnType;
}

type GenericReturnType<ReturnType, F> = F extends Callable<ReturnType>
  ? ReturnType
  : never;
```

Now using our `GenericReturnType` we can infer the correct return type:

```js
type IdentityType = GenericReturnType<string, typeof identity>; // => string
type IdentityType = GenericReturnType<number, typeof identity>; // => number
```

When it comes to generic functions we might be dealing with suboptimal conditions currently. The above `GenericReturnType` will work with the _identity_ function but might break when dealing with more complex generic functions.

On a side note, the above `GenericReturnType` works due to the fact that interfaces in TypeScript can describe function types. Take a look at the following example:

```js
interface GetInt {
    (a: string): number;
}

const getInt: GetInt = (a) => parseInt(a);

type A = ReturnType<typeof getInt>; // => number
```

We should have a better understanding of how `ReturnType` functions now and where we might gain some benefits when using it in our application.


If you have any questions or feedback please leave a comment here or connect via Twitter: [A. Sharif](https://twitter.com/sharifsbeat)