2 votes

Comment indiquer le type de retour lorsqu'il y a plusieurs types possibles en TypeScript ?

J'essaie d'écrire des types autour d'un client de l'API Axios mais je ne comprends pas la bonne façon d'indiquer au compilateur le type de retour que j'attends.

Un exemple simplifié :

import axios, { AxiosResponse } from "axios";

interface BaseApiResponse extends AxiosResponse { }

interface ApiCollectionResponse<T> extends BaseApiResponse {
    data: T[]
    meta: {
        totalCount: number
        totalPages: number
    }
}

interface ApiResourceResponse<T> extends BaseApiResponse {
    data: T
}

type ApiResponse<T> = ApiCollectionResponse<T> | ApiResourceResponse<T>

const apiAction = <T>(url: string, onSuccess: (response: ApiResponse<T>) => void) => {
    axios
        .request({ url })
        .then(({ data }) => {
            onSuccess(data)
        })
}

interface User {
    name: string
}

const loadUsers = () => 
    apiAction<User>('/users', (data) => alert(data.meta.totalCount))

Les données de réponse peuvent être soit un ApiCollectionResponse o un ApiResourceResponse . Le compilateur se plaint à juste titre que la propriété meta n'existe pas sur le site ApiResourceResponse l'interface.

Comment exprimer que cet appel à apiAction se traduira par un ApiCollectionResponse valeur de retour ?

1voto

ford04 Points 112

L'endroit où l'on tape les données récupérées ne devrait pas avoir beaucoup d'importance, tant que tout est encapsulé dans le même module API/axios. Pour le module de consommation, il suffit de loadUsers ou d'autres méthodes exportées.

Vous pouvez faire l'une des choses suivantes :

1.) Définir les méthodes explicites apiActionUsers , apiActionXXX etc. (le plus simple, si vous voulez mon avis) :

function apiActionUsers() {
  apiAction<User>("/users", data =>
    alert((data as ApiCollectionResponse<User>).meta.totalCount)
  )
}

Au lieu d'un casting brut, vous pouvez également définir un type de protection pour distinguer les types possibles de ApiResponse .

2.) Utilisation fonction overloards :

type ApiAction = {
  <T>(
    url: "/users",
    onSuccess: (response: ApiCollectionResponse<T>) => void
  ): void
  <T>(
    url: "/other-resource",
    onSuccess: (response: ApiResourceResponse<T>) => void
  ): void
}

const apiAction: ApiAction = (
  url: string,
  onSuccess: (response: any) => void
) => {
  axios.request({ url }).then(onSuccess)
}

// works!
apiAction<User>("/users", data => alert(data.meta.totalCount))

Voir le site aquí pour un exemple de surcharge de fonctions.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X