1

I want to send an http request and return the result using typescript, before send the http request, I want to get the token from google chrome local storage and put the token into http header. This is my typescript code looks like:

api_post:<T>(url: string, data: any): Promise<T> => {
    chrome.storage.local.get("token", function (result:any) {
        return fetch(url, {
            method: 'POST',
            headers: {
                'Content-type': 'application/json',
                'x-access-token': result,
            },
            body: JSON.stringify(data),
        })
            .then(response => {
                if (!response.ok) {
                    throw new Error(response.statusText);
                }
                return response.json() as Promise<T>;
            });
    });  
},

the problem is the promise return from the inner of an async code block, this function shows error:

interface Promise<T>
Represents the completion of an asynchronous operation

A function whose declared type is neither 'void' nor 'any' must return a value.ts(2355)

what should I do to return the promise inside the chrome local storage get and make the code works?

spark
  • 663
  • 1
  • 5
  • 18
  • 1
    I would recommend converting the arrow function into an `async` method, and using `await` statements instead of callbacks. First GET the token, then prepare the POST using the response from the GET, and then finally return the response from the POST. – Ross Gatih Feb 13 '22 at 07:27
  • 1
    `return fetch(...` is inside, and therefore belongs to `function (result:any) {`. Your `api_post` function has not return. But the declared return type is `Promise` – Thomas Feb 13 '22 at 07:37

3 Answers3

2

I would use the Promise constructor. Then, resolve the final desired value in the chain, and reject any errors.

const api_post = <T>(url: string, data: any): Promise<T> => {
    return new Promise((resolve, reject) => {
        chrome.storage.local.get("token", function (result: any) {
            return fetch(url, {
                method: "POST",
                headers: {
                    "Content-type": "application/json",
                    "x-access-token": result,
                },
                body: JSON.stringify(data),
            }).then((response) => {
                if (!response.ok) {
                    reject(new Error(response.statusText));
                    return;
                }
                resolve(response.json() as Promise<T>);
            });
        });
    });
};
Jordan Wright
  • 111
  • 1
  • 4
1

To follow-up on my comment, you could do something like:

api_post: async (url: string, data: any): Promise<T> => {
    const { result } = await chrome.storage.local.get("token");
    const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-type': 'application/json',
                'x-access-token': result,
            },
            body: JSON.stringify(data),
        });
    return response;
},

Note: This is just to give you an idea of how you could refactor your method using async/await. This code will probably require some tweaking.

Ross Gatih
  • 649
  • 4
  • 9
  • 1
    I do like this way at beginning of coding, but this will make all nest invoke function async. @Ross Gatih – spark Feb 13 '22 at 08:32
  • 1
    @spark an `async function` is simply a function that *always* returns a `Promise`. You don't get around that Promise, your only choice is whether you write `await api_post()` or `api_post().then(...)` – Thomas Feb 13 '22 at 14:12
1

Just throwing in another snippet, since OP seem to dislike async/await from Ross Gatih' answer and I don't like the new Promise antipattern from Jordan Wrights answer

const api_post = <T>(url: string, data: any): Promise<T> => {
  return chrome.storage.local.get("token")
    .then((result: any) => fetch(url, {
      method: "POST",
      headers: {
        "Content-type": "application/json",
        "x-access-token": result,
      },
      body: JSON.stringify(data),
    }))
    .then((response) => {
      if (!response.ok) {
        throw new Error(response.statusText);
      }
      return response.json();
    });
};
Thomas
  • 11,958
  • 1
  • 14
  • 23