我已经在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的新手,所以请多多指教!
答案 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(' '));
});
请注意如何推断参数类型。