Как набрать Axios.all, когда каждое обещание имеет другой тип возврата - PullRequest
0 голосов
/ 19 сентября 2018

У меня есть два запроса Axios get, для которых типы возврата были явно объявлены.Вот упрощенный пример:

interface O1 {
   prop1: string;
   prop2: boolean;
}

interface O2 {
   prop3: number;
   prop4: string;
}

interface Request<T> {
   message: string;
   data: T
}

Используя эти интерфейсы, я набрал свои запросы и набрал также объект результата:

const getO1 = () => Axios.get<Request<O1>>("/API/O1");
const getO2 = () => Axios.get<Request<O2>>("/API/O2");

Теперь мне нужно сделать эти вызовы параллельно, поэтому я пробовал Axiox.all, но TypeScript жалуется, что типы O1 и O2 не совпадают.В частности, я пытался:

const getAll = () => Axios.all([getO1(), getO2()]);

Из того, что я вижу, TypeScript ожидает, что в случае all все результаты будут иметь одинаковый тип (структуру).Есть ли способ иметь типизированный одновременный вызов?(с использованием Axios v0.18 и TypeScript v3.0.3)

Ответы [ 2 ]

0 голосов
/ 19 сентября 2018

К сожалению, декларация для Axios.all не очень хороша.То, как оно напечатано, нельзя передать в кортеж.

export interface AxiosStatic extends AxiosInstance {
  all<T>(values: (T | Promise<T>)[]): Promise<T[]>;
}

Параметр должен быть массивом одного типа T.Typescript не будет выводить объединение для T и не может выводить кортеж там, где ожидается массив.

Мы можем посмотреть, как набирается Promise.all (который поддерживает кортежи)

all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
// ...
all<T1, T2, T3, T4>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): Promise<[T1, T2, T3, T4]>;
all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>;
all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
all<T>(values: (T | PromiseLike<T>)[]): Promise<T[]>;

Мы видим, что они используют много перегрузок для поддержки кортежей.

Если обещания Axios соответствуют спецификациям, попробуйте использовать Promise.all.Типы работают, но я сам не проверял поведение во время выполнения.

const getAll = () => Promise.all([getO1(), getO2()]) //() => Promise<[AxiosResponse<Request<O1>>, AxiosResponse<Request<O2>>]>

Или вы можете придерживаться версии axios и использовать некоторые утверждения типа:

const getAll = () => Axios.all<{}>([getO1(), getO2()]) as unknown as AxiosPromise<[Request<O1>, Request<O2>]>

Просто веселообратите внимание, что в 3.1 мы сможем набрать all без 10 перегрузок:

type PromiseResult<T> = T extends AxiosPromise<infer R>? R: T
type ArrayPromiseResult<T extends (any | AxiosPromise<any>)[]> = { [P in keyof T]: PromiseResult<T[P]> }
declare function all<T extends [] | (any | AxiosPromise<any>)[]>(values: T): AxiosPromise<ArrayPromiseResult<T>>

let result = all([getO1(),getO2()]) // result is AxiosPromise<[Request<O1>, Request<O2>]>
0 голосов
/ 19 сентября 2018

Вы можете создать базовый интерфейс и позволить вашим интерфейсам O1 и O2 расширять этот интерфейс.Используйте базовый интерфейс в качестве параметра общего типа внутри оператора Axios.all.

  import Axios from 'axios';

    //base interface
    interface axiosResponse{}

    //extend the base interface in both interfaces
    interface O1 extends axiosResponse {
        prop1: string;
        prop2: boolean;
    }

    interface O2 extends axiosResponse {
        prop3: number;
        prop4: string;
    }

    interface Request<T> {
        message: string;
        data: T
    }

    const getO1 = () => Axios.get<Request<O1>>("/API/O1");
    const getO2 = () => Axios.get<Request<O2>>("/API/O2");

    //specify the base interface type as the generic type parameter
    const getAll = () => Axios.all<axiosResponse>([getO1(), getO2()]).then( r => {
      const result: O1 = <O1>r[0];
      const result2: O2 = <O2>r[1];
    })
...