As of TypeScript 3.1, the `lib.es5.d.ts`

file provides a couple of predefined types that are very helpful when trying to write generic higher-order functions. In this post, I’m going to show an example of using the `Parameters`

and `ReturnType`

predefined types for just that purpose.

## The Types

TypeScript 2.8 added the `ReturnType`

type, and TypeScript 3.1 added the `Parameters`

type. Here are the definitions as of TypeScript 3.1:

```
/**
* Obtain the parameters of a function type in a tuple
*/
type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
/**
* Obtain the return type of a function type
*/
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;
```

## Higher-Order Function

Here’s a higher-order function that can decorate any given function so that it logs how long the given function took to run. I don’t want to lose any type checking by decorating my functions, so the higher-order function needs to be able to preserve the types of the given function.

```
function logDuration<T extends (...args: any[]) => any>(func: T): (...funcArgs: Parameters<T>) => ReturnType<T> {
const funcName = func.name;
// Return a new function that tracks how long the original took
return (...args: Parameters<T>): ReturnType<T> => {
console.time(funcName);
const results = func(...args);
console.timeEnd(funcName);
return results;
};
}
```

## Try It Out

Here’s a simple function that just adds two numbers together:

```
function addNumbers(a: number, b: number): number {
return a + b;
}
```

`addNumbers`

has the following type signature:

```
function addNumbers(a: number, b: number): number
```

It can be decorated using `logDuration`

so we can monitor how long it takes to execute each time it’s called.

```
const addNumbersWithLogging = logDuration(addNumbers);
```

If you check the types on `addNumbersWithLogging`

, you’ll see that they match the input function exactly:

```
const addNumbersWithLogging: (a: number, b: number) => number
```

And when calling the new function, you’ll now see how long it took to execute:

```
addNumbersWithLogging(5, 3);
> addNumbers: 0.193ms
```

## Summary

Being able to write correctly typed, generic, higher-order functions is extremely powerful. Logging how long a function takes to execute is just one simple example, but the possible uses are endless.