DEV Community

Nhan Nguyen
Nhan Nguyen

Posted on

Beginner's TypeScript #9

Image description

Typing Promises and Async Requests

We have a function called fetchLukeSkywalker:

export const fetchLukeSkywalker = async (): LukeSkywalker => {
  const data = await fetch("<https://swapi.dev/api/people/1>").then((res) => {
    return res.json();
  });

  return data;
}
Enter fullscreen mode Exit fullscreen mode

It goes to the Star Wars API at swapi.dev and fetches people/1, corresponding to Luke Skywalker.

There is a LukeSkywalker type that includes properties based on what the API includes in the response:

interface LukeSkywalker {
  name: string;
  height: string;
  mass: string;
  hair_color: string;
  skin_color: string;
  eye_color: string;
  birth_year: string;
  gender: string;
}
Enter fullscreen mode Exit fullscreen mode

However, TypeScript is showing us an error on the return type:

Type 'LukeSkywalker' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.
Enter fullscreen mode Exit fullscreen mode

We will figure out how to update the return type annotations to make TypeScript happy.

👉 Solution:

Do What TypeScript Suggests:

In the starting point of the code, hovering over the error message in VS Code pops up a message:

The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<LukeSkywalker>'?
Enter fullscreen mode Exit fullscreen mode

We get this error because the fetchLukeSkywalker function is async, so the type returned will be a Promise.

Following TypeScript's suggestion to write Promise will fix this error:

export const fetchLukeSkywalker = async (): Promise<LukeSkywalker> => {
Enter fullscreen mode Exit fullscreen mode

Note that this syntax is similar to the Array syntax we saw earlier. But unlike arrays, there's only one way to use Promise.

This solution works well, and is probably what I would recommend.

Type the Fetched Data Response:

The data returned from a fetch request will be typed as any by default.

Even though we know from the API what our response will contain, TypeScript has no idea. That means the any type does not give us any autocomplete when we use it.

export const fetchLukeSkywalker = async () => {
  // `data` will be typed as `any`
  const data = await fetch(
Enter fullscreen mode Exit fullscreen mode

But because we have awaited the fetch, we can type data as LukeSkywalker:

const data: LukeSkywalker = await fetch(
Enter fullscreen mode Exit fullscreen mode

This would give us the autocomplete because it's been properly typed.

Now, when we hover over the fetchLukeSkywalker function declaration, we can see that TypeScript has inferred the return type of the function to be Promise just like we saw in the prior solution.

Cast Data as a Type:

In the cases we have looked at so far, we are kind of lying to ourselves a little bit.

TypeScript does not know what we are going to return, so we have to tell it. But really, we do not know what the result of our fetch is going to be.

This is where this solution comes in:

export const fetchLukeSkywalker = async () => {
  const data = await fetch("<https://swapi.dev/api/people/1>").then((res) => {
    return res.json();
  });

  // cast the data to LukeSkywalker
  return data as LukeSkywalker;
}
Enter fullscreen mode Exit fullscreen mode

The ** return data as LukeSkywalker** line casts the fetch response to our LukeSkywalker type.

When working with fetch requests, we should either cast the return data as a type or assign a type to the data when the request is made.

✍️ More About Casting:

Casting allows us to let anyone become LukeSkywalker:

const uri = {} as LukeSkywalker
Enter fullscreen mode Exit fullscreen mode

Compare the above to if we said uri was assignable to LukeSkywalker:

This would give us errors because the object does not include the appropriate properties.

Generally speaking, the assigning syntax is safer than the as syntax and is probably what you should do in most cases.


I hope you found it useful. Thanks for reading. 🙏

Let's get connected! You can find me on:

Top comments (0)