Typing a function wrapper with TypeScript
My task was simple: write a function wrapper to measure the time it takes to execute a function. It’s easy to write a function wrapper in JavaScript but in TypeScript this is hard because we need to preserve the types of the wrapped function. It took me a while to figure out how do this so I’m leaving this here so future me doesn’t have to waste as much time as past me did.
function instrumentFn<F extends (...args: any[]) => ReturnType<F>>(id: string, fn: F) {
return (...args: Parameters<F>) => {
const t1 = performance.now();
const result = fn(...args);
const t2 = performance.now();
console.log(`${id} took ${t2 - t1}ms`);
return result;
};
}
The tricky parts are these:
F extends (...args: any[]) => Type
to typefn
as a generic function.ReturnType<Type>
to get the return type offn
.Parameters<Type>
to get the types of the parameters offn
.
And here’s an example of using instrumentFn
:
function fibonacci(n: number): number {
if (n < 1) {
return 0;
} else if (n <= 2) {
return 1;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
const instrumentedFibonacci = instrumentFn('fibonacci', fibonacci);
instrumentedFibonacci(30);
// fibonacci took 11ms