The Utils Folder 10 exercises
solution

Type Inference in Function Parameters

Here's how PromiseFunc is currently defined:


type PromiseFunc<TResult> = (...args: any[]) => Promise<TResult>;

The first thing to do is figure out the types of the arguments being passed in. Currently, they're set to one value, but they need to be different based on the type of funct

Loading solution

Transcript

00:00 OK, so the first job here is to figure out how to infer the type of these arguments being passed in, because currently they're set to one value, but in fact we know that they need to be different based on the type of the function that's being passed in. So we're going to say args, like this, is T args.

00:19 So inside here we're basically spreading in all of those args, and we're not going to do it like this, we're not going to say T args is an array of T args, we actually want to capture the entire array here. Now what we're doing here is it says cannot find name T args, so we're going to add that as the first type parameter of the promise func.

00:38 I like to make it so that the order in which they're in the type parameters is the order they then appear in the resulting signature. Makes sense. And we're getting an error inside here saying a rest parameter must be of an array type. Now T args could be anything. It could be sort of defaults to unknown here.

00:55 So we need to make sure that whatever's passed into T args is an array type. So we can say it extends any array. This doesn't mean it's going to be inferred as any array, it just means it must be any kind of array. And this means that error goes away. So now promise func is expecting two type arguments, so we need to pass it those type arguments.

01:15 So let's say T args is there, it's not giving us the proper autocomplete there, and it says cannot find name T args, so we'll add that again into the type parameter of our generic function. So now T args is here, and again I've put it T args T result, just to make sure it's

01:34 compatible with the list of arguments here. And we're going to need the same constraint on it, because it says type T args does not satisfy the constraint any array. So let's copy and paste that constraint and stick it in there. And now this is good, and we're getting an interesting error here.

01:51 The error we're getting is argument of type any array is not assignable to parameter of type T args. It could match, but it doesn't always match. And this is because this args any array inside here, this is the spot where we need to use

02:07 our T args, because that's the whole point of what we've been pulling through here. We've got our T args inferring from the promise func that we're passing in, so in this case name string. And then we need to make sure that the function that's returned, which is this function, has the same arguments as that. And now everything just works.

02:26 So we have our safe function here, and you can see that in the first type parameter, it's inferring a tuple here, name string. And inside there, in the second one, this is the return value. So it's requiring name string, and it's returning a string. We can say ID is like a number here, if we want to, and then we can see that that gets

02:46 inferred as well. So we get name string ID number, and now the function down here, it's expecting an ID number. So it's, yeah, got to pass that in 1, 2, 3. Amazing. So there we go. Now this is really nice because it also works for this case too, where we don't want to pass in anything.

03:04 In this case, it's just inferring a tuple here. Now, why didn't we do it so it was like targs array like this? And now we can remove the constraint on targs and this constraint too. The reason why is that actually, first of all, we need to probably type this as well. Yeah.

03:22 This means you don't actually get the inference that you think, because we know from the parameters exercise a while ago, that all of the function arguments are actually a tuple here. Whereas when we infer kind of like never in this position, what we end up with is you can pass in as many arguments as you want, but they're all going to be never.

03:41 And inside here, we can actually infer pass as many arguments as we want in terms of like args string array. But this isn't actually the type of our function here. So this is something to bear in mind when you're basically doing any kind of inference to do with function parameters is that you want to make sure that you're capturing the

03:59 entire arguments like this as a tuple instead of doing something like targs array like this. This is a very, very common mistake, but the main core of this exercise is understanding that you can use multiple type arguments, both in generic functions and in generic types.