我在Typescript中使用window.fetch,但我无法将响应直接转换为我的自定义类型:
我正在通过将Promise结果转换为中级'任何'来解决这个问题。变量。
这样做的正确方法是什么?
import { Actor } from './models/actor';
fetch(`http://swapi.co/api/people/1/`)
.then(res => res.json())
.then(res => {
// this is not allowed
// let a:Actor = <Actor>res;
// I use an intermediate variable a to get around this...
let a:any = res;
let b:Actor = <Actor>a;
})
答案 0 :(得分:33)
以下是一些示例,从基本到请求和/或错误处理后添加转换:
// Implementation code where T is the returned data shape
function api<T>(url: string): Promise<T> {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(response.statusText)
}
return response.json<T>()
})
}
// Consumer
api<{ title: string; message: string }>('v1/posts/1')
.then(({ title, message }) => {
console.log(title, message)
})
.catch(error => {
/* show error message */
})
通常,您可能需要在将数据传递给使用者之前对数据进行一些调整,例如,展开顶级数据属性。这很简单:
function api<T>(url: string): Promise<T> {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(response.statusText)
}
return response.json<{ data: T }>()
})
.then(data => { /* <-- data inferred as { data: T }*/
return data.data
})
}
// Consumer - consumer remains the same
api<{ title: string; message: string }>('v1/posts/1')
.then(({ title, message }) => {
console.log(title, message)
})
.catch(error => {
/* show error message */
})
我认为您不应该直接在此服务中直接捕获错误,而只是允许它冒泡,但如果您需要,您可以执行以下操作:
function api<T>(url: string): Promise<T> {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(response.statusText)
}
return response.json<{ data: T }>()
})
.then(data => {
return data.data
})
.catch((error: Error) => {
externalErrorLogging.error(error) /* <-- made up logging service */
throw error /* <-- rethrow the error so consumer can still catch it */
})
}
// Consumer - consumer remains the same
api<{ title: string; message: string }>('v1/posts/1')
.then(({ title, message }) => {
console.log(title, message)
})
.catch(error => {
/* show error message */
})
自从不久前写这个答案以来,有一些变化。如评论中所述,response.json<T>
不再有效。不确定,无法找到它被删除的位置。
对于更高版本,您可以执行以下操作:
// Standard variation
function api<T>(url: string): Promise<T> {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(response.statusText)
}
return response.json() as Promise<T>
})
}
// For the "unwrapping" variation
function api<T>(url: string): Promise<T> {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(response.statusText)
}
return response.json() as Promise<{ data: T }>
})
.then(data => {
return data.data
})
}
答案 1 :(得分:1)
如果你看一下@types/node-fetch,你会看到身体定义
const filterObjectArray = (arr, filterArr) => (
arr.filter( el =>
filterArr.some( f =>
f.userid === el.userid && f.projectid === el.projectid
)
)
);
console.log(filterObjectArray(myArray, myFilter))
这意味着您可以使用泛型来实现您想要的效果。我没有测试这段代码,但它看起来像这样:
export class Body {
bodyUsed: boolean;
body: NodeJS.ReadableStream;
json(): Promise<any>;
json<T>(): Promise<T>;
text(): Promise<string>;
buffer(): Promise<Buffer>;
}
答案 2 :(得分:1)
实际上,在打字稿中的几乎任何地方,只要将要传递的类型兼容,就可以按需要将值传递给具有指定类型的函数。
话虽如此,以下作品...
fetch(`http://swapi.co/api/people/1/`)
.then(res => res.json())
.then((res: Actor) => {
// res is now an Actor
});
我想将所有http调用包装在一个可重用的类中-这意味着我需要某种方式让客户端以所需的形式处理响应。为此,我接受了回调lambda作为包装方法的参数。 lambda声明接受如下所示的任何类型...
callBack: (response: any) => void
但是在使用中,调用者可以传递一个lambda来指定所需的返回类型。我从上面这样修改了我的代码...
fetch(`http://swapi.co/api/people/1/`)
.then(res => res.json())
.then(res => {
if (callback) {
callback(res); // Client receives the response as desired type.
}
});
以便客户端可以使用类似...的回调来调用它。
(response: IApigeeResponse) => {
// Process response as an IApigeeResponse
}