You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Promise.all sometimes infers incorrect typesΒ #52601
Multiple files are needed to repro this bug. See the test repo. The relevant error is:
exportasyncfunctiontestPromiseAll(docs: string[]){constrequests=docs.map(asyncdoc=>fetch("/doc"));constresponses=awaitPromise.all(requests);for(constresofresponses){awaitres.blob();// Property 'blob' does not exist on type 'Promise<Response>'.}}
π Actual behavior
Code fails to build with:
Property 'blob' does not exist on type 'Promise<Response>'.
This is because the return type of Promise.all() becomes a Promise<Array<Promise<Response>>> instead of a Promise<Array<Response>>.
in the past (probably 4.7.x or even 4.6.x) i had a vaguely similar problem without Promise.all involved at all, just some large-ish function call expression being awaited, and tsc complaining it could not assign to the variable because the types were mismatched.
worked perfectly fine, and at least in vscode the popup on xxx did show the expected type SomeType.
additionally,
const xxx:Promise<SomeType> = something();
worked fine, too.
to me the whole thing felt like the mechanism behind await did something strange after looking into the expected type derived from the variable's type annotation, but as i have no idea how the actual implementation works, my assumption is probably completely wrong :)
The former is intended for arrays and the latter for tuples, but arrays are sometimes getting matched with the tuple overload. Moving the definitions into the same file and declaring the array one first solved my issue.
(Per Typescript docs, TypeScript chooses the first matching overload, but I'm not sure what this behavior is if the overloads are specified in separate files. Probably it's undefined?)
There's nearly identical code in these three examples. It seems strange that only one of the examples is typed incorrectly. Please forgive me, but I would love to understand why this is not considered a bug with this unusual behavior.
When starting from Promise<string> it works. With Promise<string[]> , the type is lost after Promise.all() (see the difference between line 7 and line 10). Could you explain how this works?
With the third example, why would .then(x => x) fix the types when x is unchanged?
Why would as const be necessary? The example is dealing with an inline literal array, how can that be assigned to something else?
If the call to Promise.all() is pulled out to a var and returned, the type problems go away as well. This is the exact same value as returning the result from Promise.all(), so why would the types differ?
This behavior is inconsistent. A developer would have to employ a trick only when using Promise.all() in a promise chain when the prior resolved value is an array.
Activity
JavaScriptBach commentedon Feb 4, 2023
Possibly also related to #51993
RyanCavanaugh commentedon Feb 4, 2023
We'd need some way to reproduce this
ritschwumm commentedon Feb 4, 2023
no idea whether this is helpful or even related:
in the past (probably 4.7.x or even 4.6.x) i had a vaguely similar problem without Promise.all involved at all, just some large-ish function call expression being awaited, and tsc complaining it could not assign to the variable because the types were mismatched.
the interesting part was, that while
failed to compile,
worked perfectly fine, and at least in vscode the popup on xxx did show the expected type SomeType.
additionally,
worked fine, too.
to me the whole thing felt like the mechanism behind
awaitdid something strange after looking into the expected type derived from the variable's type annotation, but as i have no idea how the actual implementation works, my assumption is probably completely wrong :)JavaScriptBach commentedon Feb 5, 2023
I think I found the issue. The problem is there are two overloads of
Promise.all(), defined in separate files:https://github.com/microsoft/TypeScript/blob/main/lib/lib.es2015.iterable.d.ts#L227
https://github.com/microsoft/TypeScript/blob/main/lib/lib.es2015.promise.d.ts#L41
The former is intended for arrays and the latter for tuples, but arrays are sometimes getting matched with the tuple overload. Moving the definitions into the same file and declaring the array one first solved my issue.
(Per Typescript docs, TypeScript chooses the first matching overload, but I'm not sure what this behavior is if the overloads are specified in separate files. Probably it's undefined?)
JavaScriptBach commentedon Feb 7, 2023
Ryan Cavanaugh (@RyanCavanaugh) I've attached a repro to the issue. Hope you or someone else on the team could take a look. Thanks!
wjaspers commentedon Jan 26, 2026
This is still prevalent in TS5.9.3.
Playground Example
Related (to tuples):
#51993
RyanCavanaugh commentedon Jan 27, 2026
I wouldn't consider that example a bug, since it can be solved with
as const.wjaspers commentedon Jan 27, 2026
Its just an oversimplification to minimize noise in the reproduction.
The real code I encountered is several async calls working together. One returns a singular string, the rest return string[].
What is weird to me is that this works if the Promise.all is immediately followed up by an identity function.
When would someone naturally think to use
Promise.all([...]) as constin their day to day work?fidian commentedon Jan 27, 2026
There's nearly identical code in these three examples. It seems strange that only one of the examples is typed incorrectly. Please forgive me, but I would love to understand why this is not considered a bug with this unusual behavior.
Promise<string>it works. WithPromise<string[]>, the type is lost afterPromise.all()(see the difference between line 7 and line 10). Could you explain how this works?.then(x => x)fix the types whenxis unchanged?as constbe necessary? The example is dealing with an inline literal array, how can that be assigned to something else?Promise.all()is pulled out to avarand returned, the type problems go away as well. This is the exact same value as returning the result fromPromise.all(), so why would the types differ?This behavior is inconsistent. A developer would have to employ a trick only when using
Promise.all()in a promise chain when the prior resolved value is an array.typescript-bot commentedon Jan 30, 2026
This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes.
wjaspers commentedon Jan 30, 2026
Ryan Cavanaugh (@RyanCavanaugh) Could you please elaborate on Tyler Akins (@fidian) 's questions?
Type widening in the example above suggests it is hard to trust the order of Promise.all's arguments to
.then(). This seems misleading.