镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

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

Description

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:

Activity

  1. timsuchanek commented on Oct 29, 2020

    @timsuchanek
    Contributor

    I have this issue as well.
    It came up in an issue in Prisma Client

    It happens in the following code:

    declare function a(): Promise<number>
    declare function b(): Promise<string>
    
    async function main() {
      const x = await Promise.all(
        [
          ...[2].map(() => a()),
          b()
        ]
      )
    }

    Playground Link

    Could variadic tuples maybe tackle this problem?

  2. bfricka commented on Mar 9, 2021

    @bfricka

    I opened this same issue: #43157
    But closed it 10 minutes later when I double-checked the playground and realized it wasn't specific to 4.2.

  3. cbdeveloper commented on Apr 19, 2021

    @cbdeveloper

    Is my error related to this issue?

    "typescript": "^4.2.4"
    

    image

    Note: All those get...() functions return Promise<SomeType>.

    With a single promise, it's all fine. But as soon as I pass more than one promise to the array, it shows the following error:

    image

    Full error content:

    No overload matches this call.
      The last overload gave the following error.
        Argument of type '(Promise<AdminFlags> | Promise<{ all: BrandItem[]; allValues: string[]; byValue: Record<string, BrandItem>; }>)[]' is not assignable to parameter of type 'Iterable<AdminFlags | PromiseLike<AdminFlags>>'.
          The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
            Type 'IteratorResult<Promise<AdminFlags> | Promise<{ all: BrandItem[]; allValues: string[]; byValue: Record<string, BrandItem>; }>, any>' is not assignable to type 'IteratorResult<AdminFlags | PromiseLike<AdminFlags>, any>'.
              Type 'IteratorYieldResult<Promise<AdminFlags> | Promise<{ all: BrandItem[]; allValues: string[]; byValue: Record<string, BrandItem>; }>>' is not assignable to type 'IteratorResult<AdminFlags | PromiseLike<AdminFlags>, any>'.
                Type 'IteratorYieldResult<Promise<AdminFlags> | Promise<{ all: BrandItem[]; allValues: string[]; byValue: Record<string, BrandItem>; }>>' is not assignable to type 'IteratorYieldResult<AdminFlags | PromiseLike<AdminFlags>>'.
                  Type 'Promise<AdminFlags> | Promise<{ all: BrandItem[]; allValues: string[]; byValue: Record<string, BrandItem>; }>' is not assignable to type 'AdminFlags | PromiseLike<AdminFlags>'.
                    Type 'Promise<{ all: BrandItem[]; allValues: string[]; byValue: Record<string, BrandItem>; }>' is not assignable to type 'AdminFlags | PromiseLike<AdminFlags>'.
                      Type 'Promise<{ all: BrandItem[]; allValues: string[]; byValue: Record<string, BrandItem>; }>' is not assignable to type 'PromiseLike<AdminFlags>'.
                        Types of property 'then' are incompatible.
                          Type '<TResult1 = { all: BrandItem[]; allValues: string[]; byValue: Record<string, BrandItem>; }, TResult2 = never>(onfulfilled?: ((value: { all: BrandItem[]; allValues: string[]; byValue: Record<string, BrandItem>; }) => TResult1 | PromiseLike<...>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLik...' is not assignable to type '<TResult1 = AdminFlags, TResult2 = never>(onfulfilled?: ((value: AdminFlags) => 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 '{ all: BrandItem[]; allValues: string[]; byValue: Record<string, BrandItem>; }' is missing the following properties from type 'AdminFlags': showPrices, showAdsts(2769)
    lib.es2015.iterable.d.ts(226, 5): The last overload is declared here.
    

    What could this be?

  4. 4 remaining items

  5. KKrisu commented on May 12, 2022

    @KKrisu

    Seems to be resolved now on 4.6.4

  6. vietnamesekid commented on May 19, 2022

    @vietnamesekid

    You can use it this way, I tested it and it works

    const promises: Promise<number, string>[] = [promiseNumber, promiseString];
    const res = await Promise.all(promises);
  7. maapteh commented on May 19, 2022

    @maapteh

    You dont want <number, void>, what you want is that types come from their own. But it seems to be fixed :)

  8. vietnamesekid commented on May 19, 2022

    @vietnamesekid

    Mаартен - Maarten (@maapteh) Sorry for this, i tried it with types <string, number>. Yah, it seems to be fixed, so i solved my problem this way :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

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