Refactoring for Generic Types and Functions
Here's the starting point of our safeFunction
:
type PromiseFunc = () => Promise<any>;
const safeFunction = (func: PromiseFunc) => async () => {
try {
const result = await func();
return result;
} catch (e) {
if (e instanceof Error) {
return e;
}
throw e;
}
Transcript
00:00 Okay, first of all, we need to look at this safe function and think, what do we want to infer from this situation? What do we want the type argument to be? What is changing in here? Well, inside this function, the parameters are always the same, right? So it's always empty parameters. And then the thing that we're returning is different.
00:17 So it's a return one, two, three here, okay. So how do we make safe function pick up the thing that we want to return from the promise function? Because it's really just being represented by this any here. Now let's do something here. Let's say, let's imagine that this is like a T result inside here.
00:36 There's a type parameter that we want to infer in this position. So we say promise T result. That promise T result, currently the error is cannot find name T result. It's not being declared anywhere. So let's add it onto the parameter of the type here as make this promise function a generic type.
00:54 So let's put T result inside there. Now we get an error when we use promise func saying that it requires a type argument. So let's pass a type argument into here. So now the results of this promise func, like sure, we can now use it as like promise func string. And this will be a function with no parameters that returns something with a promise string.
01:13 And now we cannot find name T result here. So let's make safe function a generic function so that it can infer the idea of the value of T results. So we save that and it sort of reformats and now everything works. Because now in safe function, we can see that it's being inferred as a number.
01:32 If we return a Boolean from this instead, then safe function will return a Boolean and it will be inferred all the way through. And we can see inside the arguments here that func is a promise func with a Boolean in there. And we're getting back a promise Boolean or error. How cool is that? So now everything's just working. Safe function infers a string
01:52 because the function we're passing it is returns a promise, which is a string. And again, it's being inferred as the identity of that generic function there. So it's saying promise func, passing in a type argument of string. So you can combine generic types and generic functions to make these really clever patterns and to basically capture a lot of the complexity
02:11 inside reusable generic types.