我想编写一个 Typescript 包装器来使用 Typescript 进行类型安全的获取。我一直在谷歌上搜索,找到的最好的来源是 2016 年的这个线程。它似乎对 2016 年的人们有所帮助,但现在我无法让该代码片段发挥作用。
以下内容使 TS Linter 抱怨([ts]预期 0 类型参数,但得到 1。):
response.json<T>()
所以根据
这个线程我将其更改为以下
data => data as T
上面的选项都不起作用,因为两个调用都返回未定义。如果使用诸如
this 之类的源,我希望能够使用 {name: string, username: string},如下所示:
api<{ name: string; username: string }>('https://jsonplaceholder.typicode.com/users')
以下 then 子句:
.then(({ name, username })
如果能够详细了解如何创建包装函数来执行类型安全的获取调用,我们将不胜感激。
编辑
根据要求添加更完整的片段
api<T>(url: string): Promise<T> {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json().then(data => data as T);
})
.catch((error: Error) => {
throw error;
});
}
// consumer
this.api<{ name: string; username: string }>("https://jsonplaceholder.typicode.com/users/")
.then(({ name, username }) => {
console.log(name, username);
})
.catch(error => {
console.error(error);
});
as T
方法中使用
json
应该可以正常工作。问题是你的 json 包含一个数组,而不是单个对象。因此,如果您编写
return response.json().then(data => data[0]);
仅选择一个元素,则其余代码将起作用。您可能想要整个数组,在这种情况下,您需要更改使用者以传递预期类型的数组:
this.api<Array<{ name: string; username: string }>>("https://jsonplaceholder.typicode.com/users/")
.then(data => {
data.forEach(({ name, username }) => console.log(name, username))
})
.catch(error => {
console.error(error);
});
const res = await fetchJSON<ApiReqLogin, ApiResLogin>('api/login', { code })
ApiReqLogin - 是用于此请求的类型/接口,ApiResLogin - 用于预期响应。在服务器上,您应该确保响应的类型为 ApiResLogin,而在前端,请求的类型为 ApiReqLogin。
获取包装纸:
const fetchJSON = <Req, Res>(link: string, body: Req): Promise<{ data: Res; mes: false } | { data: false; mes: string }> => {
return new Promise(resolve => {
fetch(link, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
})
.then(res => res.json())
.then((data: Res) => {
resolve({ data, mes: false })
})
.catch(err => {
resolve({ data: false, mes: 'error' })
})
})
}