How to use fetch in typescript

I use window.fetch in Typescript, but I cannot attribute the response directly to my custom type:

I crack my way around this by discarding the Promise result of the intermediate variable "any".

What would be the right way to do this?

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; }) 
+23
source share
2 answers

The following are a few examples, from basic to adding transformations after processing the request and / or error:

The main ones:

 // 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 */ }) 

Data conversion:

Often, you may need to make some changes to the data before it is passed to the consumer, for example, by expanding the top-level data attribute. This is straightforward:

 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 */ }) 

Error processing:

I would say that you should not directly catch errors directly in this service, just letting it bubble, but if you need to, you can do the following:

 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 */ }) 

edit

There have been some changes since this answer was written. As mentioned in the comments, response.json<T> no longer valid. Not sure I could not find where it was removed.

For later releases you can do:

 // 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 }) } 
+32
source

If you look @ types / node-fetch , you will see a body definition

 export class Body { bodyUsed: boolean; body: NodeJS.ReadableStream; json(): Promise<any>; json<T>(): Promise<T>; text(): Promise<string>; buffer(): Promise<Buffer>; } 

This means that you can use generics to achieve what you want. I have not tested this code, but it looks something like this:

 import { Actor } from './models/actor'; fetch(`http://swapi.co/api/people/1/`) .then(res => res.json<Actor>()) .then(res => { let b:Actor = res; }); 
+1
source

Source: https://habr.com/ru/post/1261144/


All Articles