Announcing: A Free Book, A New Course, A Huge Price Cut...
It's a massive ship day. We're launching a free TypeScript book, new course, giveaway, price cut, and sale.
Here's a challenge for you. Our retry
function below doesn't infer the type of the resolved promise. Can you fix it?
The error above is happening because we're using any
as the return type of the promise in the retry
function:
async function retry(
fn: () => Promise<any>,
retries: number = 5
): Promise<any> {
// ...
}
This means that when we call the retry
function, TypeScript can't infer the type of the resolved promise. It's just any
.
This is bad, because any
disables type checking on anything it's applied to. This means that just by using our retry
function, we're losing type safety on whatever we pass into it.
This is a common problem when you're working with reusable functions in TypeScript - it's tempting to slap an any
on there and move on. But with just a bit of extra work, we can make our functions much more flexible and type-safe.
Instead of using any
, we can use a type parameter to make the retry
function more flexible:
async function retry <T >(
fn : () => Promise <T >,
retries : number = 5
): Promise <T > {
try {
return await fn ();
} catch (err ) {
if (retries > 0) {
console .log ("Retrying...");
return await retry (fn , retries - 1);
}
throw err ;
}
}
We've added a type parameter T
to the retry
function. We're then referencing it in the fn
parameter as the thing we expect to get back from our promise. Finally, we use it as the return type of the retry
function.
This means that when we call the retry
function, TypeScript can infer the type of the resolved promise. It's no longer any
- it's the type we return from our promise.
const getString = () => Promise .resolve ("hello");
retry (getString ).then ((str ) => {
// str is string, not any!
console .log (str );
});
We can name T
anything we like: TData
or TResponse
are common choices. I like using T
at the start to represent 'type parameter'.
Our retry
function is now a generic function - it captures type information from the runtime values passed in. This means it's a lot more reusable and safe to use.
If you're interested in learning more about generics, my course Total TypeScript has an entire module covering them in-depth.
Or, you could check out the other articles I've written on generics on this site.
Share this article with your friends
It's a massive ship day. We're launching a free TypeScript book, new course, giveaway, price cut, and sale.
Learn why the order you specify object properties in TypeScript matters and how it can affect type inference in your functions.
Learn how to use corepack
to configure package managers in Node.js projects, ensuring you always use the correct one.
Learn how to strongly type process.env in TypeScript by either augmenting global type or validating it at runtime with t3-env.
Discover when it's appropriate to use TypeScript's any
type despite its risks. Learn about legitimate cases where any
is necessary.
Learn why TypeScript's types don't exist at runtime. Discover how TypeScript compiles down to JavaScript and how it differs from other strongly-typed languages.