Skip to content

Incorrect type inference of Promise.all when spreading Promise arrays #40330

Closed
@peterjuras

Description

@peterjuras

TypeScript Version: 4.0.2 (but also the version in the Playground)

Search Terms:

Promise.all type inference

Code

async function test() {

    const promiseNumber = Promise.resolve(1);
    const promiseVoid = async () => {}

    await Promise.all([
        promiseNumber,
        ...[promiseVoid()]
    ])
}

Expected behavior:

The Promise.all call should not throw any compile time errors due to type mismatches, since Promise.all simply returns the values of the array and waits until resolution if the value is a promise.

Actual behavior:

A compile time error is thrown:

No overload matches this call.
  The last overload gave the following error.
    Argument of type '(Promise<number> | Promise<void>)[]' is not assignable to parameter of type 'Iterable<number | PromiseLike<number>>'.
      The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
        Type 'IteratorResult<Promise<number> | Promise<void>, any>' is not assignable to type 'IteratorResult<number | PromiseLike<number>, any>'.
          Type 'IteratorYieldResult<Promise<number> | Promise<void>>' is not assignable to type 'IteratorResult<number | PromiseLike<number>, any>'.
            Type 'IteratorYieldResult<Promise<number> | Promise<void>>' is not assignable to type 'IteratorYieldResult<number | PromiseLike<number>>'.
              Type 'Promise<number> | Promise<void>' is not assignable to type 'number | PromiseLike<number>'.
                Type 'Promise<void>' is not assignable to type 'number | PromiseLike<number>'.
                  Type 'Promise<void>' is not assignable to type 'PromiseLike<number>'.
                    Types of property 'then' are incompatible.
                      Type '<TResult1 = void, TResult2 = never>(onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<...>' is not assignable to type '<TResult1 = number, TResult2 = never>(onfulfilled?: ((value: number) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | null | undefined) => PromiseLike<...>'.
                        Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible.
                          Types of parameters 'value' and 'value' are incompatible.
                            Type 'void' is not assignable to type 'number'.(2769)

Workaround:

Setting the generic type argument of Promise.all to void | number works, but this is a step backwards after TypeScript added better Promise.all inference and it should know that the first argument that will be returned from the call will be a number:

// Workaround which throws no errors:
async function test() {

    const promiseNumber = Promise.resolve(1);
    const promiseVoid = async () => {}

    await Promise.all<number | void>([
        promiseNumber,
        ...[promiseVoid()]
    ])
}

Playground Link:

https://www.typescriptlang.org/play?#code/IYZwngdgxgBAZgV2gFwJYHsI2QUxMgCgEoYBvAKHJmpik3xgAcAndAW1RBwDkE2AjHMxgBeGAAVWHLgDpmedABsAbjgIBGIgG4qNOhAYt2nHADV0qACaiYoSLGKiAfGQC+lGrYDuwVMglSJjLAiooEANq6ntRG0jx8gswANFHRMunhsSbmVsQAuql5ROSuQA

Related Issues:

Metadata

Metadata

Assignees

Labels

Fix AvailableA PR has been opened for this issueNeeds InvestigationThis issue needs a team member to investigate its status.RescheduledThis issue was previously scheduled to an earlier milestone

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions