Typescript使用基本API类型声明API响应的类型

时间:2019-12-14 19:19:07

标签: javascript typescript

我已经在fetch周围编写了一个简单的包装程序,以与返回一个项目列表的API进行通信,其中每个项目都保证至少具有一个id属性:

type fetchOptions = {};
type fetchReturn = {
  items: Array<{
    id: number;
    [key: string]: any;
  }>;
};

export const get = async (
  path: string,
  options: fetchOptions = {}
): Promise<fetchReturn> => {
  const resp = await fetch(`${API_HOST}${path}`, {
    method: 'GET',
    ...options,
  });
  return resp.json();
};

现在在组件中,我想用它来获取Todos的列表,为此我要输入一个类型:

type Todo = {
  id: number;
  name: string;
  status: string;
};

interface TodosResponse {
  items: Array<Todo>;
}

get('/todos').then((resp: TodosResponse) => { // I know resp.items is a list of Todo
  this.setState({
    todos: resp.items,
  });
});

编译器给我这个错误:

Argument of type '(resp: TodosResponse) => void' is not assignable to parameter of type '(value: fetchReturn) => void | PromiseLike<void>'.

告诉TS编译器我知道get的promise resolution值的最佳方法是什么(因为我要传递/todos)。

我可以像这样放松对fetchReturn的约束,但是我想知道是否有更好的方法来指示至少具有id属性的对象列表

type fetchReturn = {
  items: Array<any>;
}

我是TS的新手,所以请多多指教!

1 个答案:

答案 0 :(得分:0)

编译器是正确的。您正在编写的代码类型不安全。打字稿中的一个很好的经验法则是,如果必须指定回调参数的类型,那么您做错了什么。

处理这种情况的最小方法是将请求的URL段与假定的响应类型相关联。

interface Endpoints {
  '/todos': TodosResponse;
  // etc.
}

export const get = async <Endpoint extends keyof Endpoints>(
  path: Endpoint,
  options: fetchOptions = {}
): Promise<Endpoints[Endpoint]> {
  const resp = await fetch(`${API_HOST}${path}`, {
    method: 'GET',
    ...options,
  });
  return resp.json();
};

现在您可以这样称呼

get('/todos').then(resp => {
  console.log(resp.items[0].name.split(' '));
});

请注意如何推断参数类型。