Essential Types And Notations 20 exercises
solution

Adding Types to an Async Function

You might be tempted to try passing a type argument to fetch, similar to how you would with Map or Set.

However, hovering over fetch, we can see that it doesn't accept type arguments:


// this won't work!
const response = fetch<number>("https://api.example.com/data"); // red

Loading solution

Transcript

00:00 Okay, let's take a look at a few of the different solutions here. The first one that comes to mind is you might be thinking, well, shouldn't I be able to pass a type argument to fetch similar to map or set? Well, no, unfortunately, just like json.pass, this is one of the ones that you can't add a type annotation to. How about .json?

00:18 Maybe I could be able to pass in like this one inside here, but no, expected zero type arguments, but got one. So it's not expecting to be passed a type argument. So then what we could do, certainly a very nice way to do it, is by saying data is number like this.

00:35 This works because data was any before, and this await response.json returns any. So now what we're doing is we're basically just putting any into a slot that requires a number, and it's happy. So that's one way to do it. The way that I recommend you do it, though, is by adding a return type to this function.

00:54 So what we can do is after these little parentheses here, we can add a return type and we can say fetch data returns number. Okay, now we're getting somewhere. Now data is typed as number, except there's an error up here. The return type of an async functional method must be the global promise type.

01:13 Did you mean to write promise number? Amazing. This is an extremely rare, very, very good error message from TypeScript. And it's basically saying you should use promise number instead, because if we weren't to await this, for instance, and we still had this number set up there, then TypeScript would infer this is a number.

01:34 But in fact, we still have to await that. We need to await fetch data for it to be worth anything. So by wrapping it in promise, we make sure that this data is awaited before it can be figured out. So we've got await, not awaited, what am I doing? Await fetch data.

01:52 Now make sure that this data is typed as a number. And this is kind of like the same thing. Data here is typed as any. And so when we return any from this fetch data, it's not going to yell at us. Whereas if this was typed a string, for instance, then it would yell at us because type string is not assignable to type number,

02:12 which is what we're saying we pass back. So these return types are really useful because they let you say on the function itself what the function is supposed to return. And TypeScript will enforce that. Pretty cool.