Search code examples
typescriptes6-promise

How to define the return type for `Promise.all`?


Not sure what is going on here. Did I do something weird with my types...

const reflect = (promise): Promise<Reflection> =>
    promise.then(
        (value) => ({ value, resolved: true }),
        (error) => ({ error, rejected: true })
    );

const to = (promiseArr) => {
    return Promise.all(promiseArr.map(reflect)).then((sources: Reflection[]) => sources);
};
Argument of type '(sources: Reflection[]) => Reflection[]' is not assignable to parameter of type '(value: [unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown]) => Reflection[] | PromiseLike<Reflection[]>'.
  Types of parameters 'sources' and 'value' are incompatible.
    Type '[unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown]' is not assignable to type 'Reflection[]'.
      Type 'unknown' is not assignable to type 'Reflection'.ts(2345)


Solution

  • It depends on what your Reflection type is, but it sounds like it should probably take a type parameter of the resolve value, if the Promise resolves, probably something like

    type Reflection<T> = {
        value: T;
        resolved: true;
    } | {
        error: unknown;
        rejected: true;
    }
    

    Then, in reflect and to, make sure to denote the types of the arguments, and pass those types as the type parameters:

    const reflect = <T>(promise: Promise<T>): Promise<Reflection<T>> =>
        promise.then(
            value => ({ value, resolved: true }),
            error => ({ error, rejected: true })
        );
    
    const to = <T>(promiseArr: Array<Promise<T>>) => {
        return Promise.all(promiseArr.map(reflect)).then((sources: Array<Reflection<T>>) => sources);
    };
    

    This compiles properly, and TS detects to's type as:

    const to: <T>(promiseArr: Promise<T>[]) => Promise<Reflection<T>[]>
    

    Though, note that the last .then in to isn't doing anything, so you can simplify it to

    const to = <T>(promiseArr: Array<Promise<T>>) => {
        return Promise.all(promiseArr.map(reflect))
    };
    

    Working demo