J'utilise window.fetch dans TypeScript, mais je ne peux pas convertir la réponse directement en mon type personnalisé:
Je corrige ce problème en convertissant le résultat de Promise en une variable intermédiaire 'quelconque'.
Quelle serait la bonne méthode pour faire cela?
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;
})
Quelques exemples suivent, allant de la base à l'ajout de transformations après la requête et/ou la gestion des erreurs:
// 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 */
})
Souvent, vous devrez peut-être apporter quelques modifications aux données avant qu'elles ne soient transmises au consommateur, par exemple, en décompressant un attribut de données de niveau supérieur. C'est simple:
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 */
})
Je dirais que vous ne devriez pas être directement en train de capturer les erreurs directement dans ce service, mais simplement de le laisser bouger, mais si vous en avez besoin, vous pouvez procéder comme suit:
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 */
})
Il y a eu quelques changements depuis l'écriture de cette réponse il y a quelque temps. Comme mentionné dans les commentaires, response.json<T>
n'est plus valide. Pas sûr, impossible de trouver où il a été retiré.
Pour les versions ultérieures, vous pouvez faire:
// 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
})
}
Si vous jetez un oeil à @ types/node-fetch , vous verrez la définition du corps.
export class Body {
bodyUsed: boolean;
body: NodeJS.ReadableStream;
json(): Promise<any>;
json<T>(): Promise<T>;
text(): Promise<string>;
buffer(): Promise<Buffer>;
}
Cela signifie que vous pouvez utiliser des génériques pour obtenir ce que vous voulez. Je n'ai pas testé ce code, mais il ressemblerait à ceci:
import { Actor } from './models/actor';
fetch(`http://swapi.co/api/people/1/`)
.then(res => res.json<Actor>())
.then(res => {
let b:Actor = res;
});