Typescript Fetch API返回Promise <T>或Promise <T []>

时间:2019-08-13 10:34:02

标签: typescript fetch-api

我正在用Typescript编写API包装程序,并且正在考虑将Fetch API与Promises结合使用。我想在请求方法中使用泛型,以便可以对绑定到提供的类型的模型进行建模,但是我对Typescript还是很陌生(并且对此保证),并且在有条件地返回Promise<T>或{{ 1}},因为并非所有请求都将返回一个数组。

这是我代码的状态,到目前为止,它还没有处于完成状态,但是可以使用。

Promise<T[]>

我可以尝试像这样有条件地返回:

export default class ApiWrapper
{
    public async request<T>(endpoint: string, method: string = 'GET', parameters: object = {}) : Promise<void|T>
    {
        var protocol = process.env.REACT_APP_APPLICATION_PROTOCOL || 'https'
        var host = process.env.REACT_APP_APPLICATION_HOST
        var port = process.env.REACT_APP_APPLICATION_PORT ? `:${process.env.REACT_APP_APPLICATION_PORT}` : ''
        var path = process.env.REACT_APP_APPLICATION_PATH || '/'

        if (!host)
        {
            // TODO:- Handle error
        }

        let body = JSON.stringify(parameters)

        return await fetch(`${protocol}://${host}${port}${path}/${endpoint}`, {
            method: method,
            body: body
        })
        .then(response => response.json() as Promise<T>)
        .then(data => {
            return data
        })
    }

    public async get<T>(endpoint: string, parameters: object = {})
    {
        return await this.request<T>(endpoint, 'GET', parameters)
    }

    public async post(endpoint: string, parameters: object)
    {
        return await this.request(endpoint, 'POST', parameters)
    }

    public async put(endpoint: string, parameters: object)
    {
        return await this.request(endpoint, 'PUT', parameters)
    }

    public async delete(endpoint: string)
    {
        return await this.request(endpoint, 'DELETE')
    }
}

尽管return await fetch(`${protocol}://${host}${port}${path}/${endpoint}`, { method: method, body: body }) .then(response => { if (Array.isArray(response.json())) { return response.json() as Promise<T[]> } else { return response.json() as Promise<T> } }) .then(data => { return data }) 无法分配给类型T。这可能真的很简单,很愚蠢甚至不可能,但是任何指针都将不胜感激。如果有

,则可以提供任何其他信息

2 个答案:

答案 0 :(得分:1)

您不需要使用不同的签名返回相同的结果。 T不仅可以是单一类型(例如stringnumber等),而且可以是类型的数组。

此外,我看不到函数在void中。如果您打算抛出错误,那么正确的签名是never

因此,该函数可以如下所示:

class ApiWrapper {
  public async request<T>(endpoint: string, method: string = "GET", parameters: object = {}): Promise<never | T> {
    let protocol, host, port, path;
    let body = JSON.stringify(parameters);

    return await fetch(`${protocol}://${host}${port}${path}/${endpoint}`, {
      method: method,
      body: body
    })
      .then(response => {
        if (response.ok) {
          return response.json();
        } else {
          throw new Error(response.statusText);
        }
      })
      .then(data => {
        return data;
      });
  }
}

(async () => {
  const apiWrapper = new ApiWrapper();
  const singleItem: string = await apiWrapper.request<string>("asdfsd");
  console.log(singleItem.endsWith);

  const arrayItemWrong: string[] = await apiWrapper.request<string>("asdfsd");
  const arrayItem: string[] = await apiWrapper.request<string[]>("asdfsd");
  console.log(arrayItem.concat);
})();

Playground

答案 1 :(得分:0)

好的,我想我已经弄明白了,尽管我确信这可能会有所缩短。

如果我使用箭头函数通过.then()回调中声明Promise的返回类型,如下所示:

return await fetch(`${protocol}://${host}${port}${path}/${endpoint}`, {
    method: method,
    body: body
})
.then(function(response): Promise<T|T[]> {
    if (response.ok) {
        if (Array.isArray(response.json())) {
            return response.json() as Promise<T[]>
        } else {
            return response.json() as Promise<T>
        }
    } else {
        throw new Error(response.statusText)
    }
})
.then(data => {
    return data
})

然后,编译器似乎接受了这一点。可能应该很明显,但是TypeScript编译器错误是一个迷宫。