Skip to content

Promise.all and Promise.allSettled infer incorrect types from Array subclasses #51993

Open

Description

lib Update Request

Configuration Check

My compilation target is ES2020 and my lib is the default.

Missing / Incorrect Definition

Promise.all
Promise.allSettled

Sample Code

declare class ArrayChild<T> extends Array<T> {}

declare const array: Array<Promise<number>>
declare const child: ArrayChild<Promise<number>>

Promise.all(array).then(a => a /* number[] */) 
Promise.allSettled(array).then(a => a /* PromiseSettledResult<number>[] */)

Promise.all(child).then(a => a /* {[K in keyof ArrayChild]: number} */) 
Promise.allSettled(child).then(a => /* {[K in keyof ArrayChild]: PromiseSettledResult<number>} */) 

Playground link

Documentation Link

Promise.all
Promise.allSettled

Possible fix

The inferred value should be of type number[] exactly like what happens with normal Array class. In the linked playground, It can be seen that Promise.all and Promise.allSettled infer the correct type with an Iterable type of object. This undesired behavior just happens with Array subclasses. I have quickly tried changing the signature from the original:

allSettled<T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: PromiseSettledResult<Awaited<T[P]>> }>;
all<T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]> }>;

to

allSettled<T extends Promise<unknown>[]>(values: T): Promise<T extends Promise<infer S>[] ? PromiseSettledResult<S>[] : never>
all<T extends Promise<unknown>[]>(values: T): Promise<T extends Promise<infer S>[] ? S[] : never>

and it works as expected: Playground link

Activity

  1. IllusionMH commented on Dec 22, 2022

    @IllusionMH
    Contributor

    This would break tuples, which (I assume), are more common use case than Array subclasses in promise methods.

    Example

  2. andrewbranch commented on Dec 22, 2022

    @andrewbranch
    Member

    Yeah, we definitely can’t break tuple inference here. Seems like there could be another way to write it, but we’ll have to weigh the complexity and performance cost against how useful it actually is on average in real code.

  3. asnaeb commented on Dec 22, 2022

    @asnaeb
    Author

    Extending Array class, while uncommon is part of the language and this bug can be a wall against libraries development, for example. I'm going to spend some time in finding a solution as soon as I get the chance!

  4. changed the title [-]Promise.all and Promise.allSettled infer incorrect types from Array child classes[/-] [+]Promise.all and Promise.allSettled infer incorrect types from Array subclasses[/+] on Dec 22, 2022
  5. asnaeb commented on Dec 25, 2022

    @asnaeb
    Author

    While I didn't test this exhaustively, It looks like it's working

    declare function all<T extends [unknown] | ArrayLike<unknown> | Iterable<unknown>>(values: T): Promise<
        T extends {[P in 0]: unknown} ? 
            {-readonly [P in keyof T]: Awaited<T[P]>} : 
                T extends ArrayLike<infer S> | Iterable<infer S> ? Awaited<S>[] : never 
    >

    Playground Link

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: lib.d.tsThe issue relates to the different libraries shipped with TypeScript

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions