Type annotation in asynchronous functions in Typescript

Asked

Viewed 74 times

2

I am new to Typescript and I have the following question. It is necessary to be explicit about the type of return of a request fetch?

const getPeoples: () => {
  userId: number,
  id: number,
  title: string,
  body: string,
}[] = async() => {
  const url =  "https://jsonplaceholder.typicode.com/posts?_limit=2"
  const response: Response = await fetch(url);
  const data = await response.json()

  return data;
}

The editor is accusing an error saying that the variable data is a guy Promise<any> (which of course) and which is not returning the type I explained. So it is bad practice to leave the code as follows?

const getPeoples: () => Promise<any> = async() => {
  const url =  "https://jsonplaceholder.typicode.com/posts?_limit=2"
  const response: Response = await fetch(url);
  const data: Promise<any> = await response.json();

  return data;
}

1 answer

4


It is not bad practice to write down the type explicitly when the type is any. Quite the contrary, it is a great practice to define explicit types when a cannot infer the type - as in this case.

You won’t be error-free, since eventually you can assign a "wrong" type, but that’s not always the case.

In this case - an HTTP request -, unless you are using an type Guard (that would bring as much type security as possible), note down a type to any is a valid option too.

The problem is that the type you are noting as function return is:

{
  userId: number;
  id: number;
  title: string;
  body: string;
}[];

And this type is different (and not attributable) to the type Promise<any>, because that guy is not a Promise.

It is also worth mentioning that all asynchronous function (annotated with async) return a promise, which also invalidates the explicit annotation.

To correct, while still keeping the explicit return, you must clarify that the function is returning a Promise something. Therefore, the return annotation should be something like:

Promise<{
  userId: number;
  id: number;
  title: string;
  body: string;
}[]>;

Promise<T> is a generic type embedded in the Typescript library. You can consult here.

This means a promise that will resolve in an object array (with the specified signature).

Then your function will look something like:

const getPeople: () => Promise<{
  userId: number;
  id: number;
  title: string;
  body: string;
}[]> = async () => {
  const url = 'https://jsonplaceholder.typicode.com/posts?_limit=2';
  const response: Response = await fetch(url);
  const data = await response.json();

  return data;
};

However, I don’t recommend using the annotation that way, since you’re giving a type to a Arrow Function, and not necessarily on his return. Personally, I would do so:

interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}

// Estamos anotando o tipo explicitamente no retorno da função:
//                          ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
async function getPeople(): Promise<Post[]> {
  const url = 'https://jsonplaceholder.typicode.com/posts?_limit=2';
  const response: Response = await fetch(url);
  const data = await response.json();

  return data;
}

See on Typescript playground.

Another option is to annotate the type directly in the variable and let Typescript infer the return of the function:

interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}

async function getPeople() {
  const url = 'https://jsonplaceholder.typicode.com/posts?_limit=2';
  const response: Response = await fetch(url);

  // Estamos anotando o tipo explicitamente na variável:
  //          ↓↓↓↓↓↓
  const data: Post[] = await response.json();

  return data;
}

See on Typescript playground.

  • 1

    Thank you so much for your help!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.