TypeScript Version: v3.7.2
Search Terms:
Promise.all, No overload matchs this call
Expected behavior:
Use a variable number of promises in a Promise.all call
Actual behavior:
If we use more than 10 promises, and these promises return different types, the compiler throws a error
Related Issues:
Code
// This works!
(async () => {
const a0: Promise<number> = Promise.resolve(0);
const a1: Promise<string> = Promise.resolve('0');
const a2: Promise<number> = Promise.resolve(0);
const a3: Promise<number> = Promise.resolve(0);
const a4: Promise<number> = Promise.resolve(0);
const a5: Promise<number> = Promise.resolve(0);
const a6: Promise<number> = Promise.resolve(0);
const a7: Promise<number> = Promise.resolve(0);
const a8: Promise<number> = Promise.resolve(0);
const a9: Promise<number> = Promise.resolve(0);
const result = await Promise.all([a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]);
})();
// If we use more than 10 promises with diferent types in a Promise.all, Promise.all throws a error
/**
* No overload matches this call.
The last overload gave the following error.
Argument of type '(Promise<number> | Promise<string>)[]' 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<string>, any>' is not assignable to type 'IteratorResult<number | PromiseLike<number>, any>'.
Type 'IteratorYieldResult<Promise<number> | Promise<string>>' is not assignable to type 'IteratorResult<number | PromiseLike<number>, any>'.
Type 'IteratorYieldResult<Promise<number> | Promise<string>>' is not assignable to type 'IteratorYieldResult<number | PromiseLike<number>>'.
Type 'Promise<number> | Promise<string>' is not assignable to type 'number | PromiseLike<number>'.
Type 'Promise<string>' is not assignable to type 'number | PromiseLike<number>'.
Type 'Promise<string>' is not assignable to type 'PromiseLike<number>'.
Types of property 'then' are incompatible.
Type '<TResult1 = string, TResult2 = never>(onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | 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 'string' is not assignable to type 'number'.(2769)
input.ts(29, 6): The last overload is declared here.
*/
(async () => {
const a0: Promise<number> = Promise.resolve(0);
const a1: Promise<string> = Promise.resolve('0');
const a2: Promise<number> = Promise.resolve(0);
const a3: Promise<number> = Promise.resolve(0);
const a4: Promise<number> = Promise.resolve(0);
const a5: Promise<number> = Promise.resolve(0);
const a6: Promise<number> = Promise.resolve(0);
const a7: Promise<number> = Promise.resolve(0);
const a8: Promise<number> = Promise.resolve(0);
const a9: Promise<number> = Promise.resolve(0);
const a10: Promise<number> = Promise.resolve(0);
const result = await Promise.all([a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]);
})();
Output
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
// This works!
(() => __awaiter(void 0, void 0, void 0, function* () {
const a0 = Promise.resolve(0);
const a1 = Promise.resolve('0');
const a2 = Promise.resolve(0);
const a3 = Promise.resolve(0);
const a4 = Promise.resolve(0);
const a5 = Promise.resolve(0);
const a6 = Promise.resolve(0);
const a7 = Promise.resolve(0);
const a8 = Promise.resolve(0);
const a9 = Promise.resolve(0);
const result = yield Promise.all([a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]);
}))();
// If we use more than 10 promises with diferent types in a Promise.all, Promise.all throws a error
(() => __awaiter(void 0, void 0, void 0, function* () {
const a0 = Promise.resolve(0);
const a1 = Promise.resolve('0');
const a2 = Promise.resolve(0);
const a3 = Promise.resolve(0);
const a4 = Promise.resolve(0);
const a5 = Promise.resolve(0);
const a6 = Promise.resolve(0);
const a7 = Promise.resolve(0);
const a8 = Promise.resolve(0);
const a9 = Promise.resolve(0);
const a10 = Promise.resolve(0);
const result = yield Promise.all([a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]);
}))();
Compiler Options
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"types": ["reflect-metadata", "swagger-express-ts"],
"outDir": "dist",
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"inlineSourceMap": true,
"lib": ["es2017"]
}
}
Playground Link: Provided
Real project prints:
Working:

Error:

You can probably use declaration merging to implement your own promise.all with 11,12,13+-tuples
A month later: "No overload with more than 150 promises"
@MartinJohns I honestly had that problem for quite a bit, before tuple types+rest args were introduced.
I ended up writing code generators that would generate N overloads for me; one for each number of arguments.
Sometimes, it would cause compile times to slow and I would have to reduce the value of N.
It was always a struggle between supporting edge cases with high N values and having sane declaration emit/compile times.
Even now, I still have problems with it, sometimes, but for trampoline types. Where I support N iterations of a recursive type and have a comment that says, "If you need > N iterations, you're doing something very suspicious"
@AnyhowStep six months later: "No overload with more than 2147483647 promises"
In all seriousness, it's always a compromise, and declaration merging and custom overloads seem like the best option for such specific corner cases.
Anyone literally passing in two billion promises to Promise.all either has a nasty bug in their code or else is doing something very, very wrong. :wink:
But yeah, it’s frustrating when you can’t easily write a single type to handle “arbitrary number of Xs” and have to resort to overloads or the like. That’s why I love changes like the recursive type aliases PR that enabled JSON-like types.
But yeah, it’s frustrating when you can’t easily write a single type to handle “arbitrary number of Xs” and have to resort to overloads or the like.
Actually you can: https://github.com/microsoft/TypeScript/issues/27179
For Promise.all:
type UnwrapPromise<T> = T extends Promise<infer R> ? R : T;
declare function PromiseAll<T extends Array<any> | [any]>(
promises: T,
): Promise<{ [K in keyof T]: UnwrapPromise<T[K]> }>;
// a infered as Promise<[number, string]>
const a = PromiseAll([
Promise.resolve(3),
Promise.resolve('foo'),
]);
// b infered as Promise<[0,1,2,3,4,5,6,7,8,9,10,11,12,13]>
const b = PromiseAll([
Promise.resolve(0 as const),
Promise.resolve(1 as const),
Promise.resolve(2 as const),
Promise.resolve(3 as const),
Promise.resolve(4 as const),
Promise.resolve(5 as const),
Promise.resolve(6 as const),
Promise.resolve(7 as const),
Promise.resolve(8 as const),
Promise.resolve(9 as const),
Promise.resolve(10 as const),
Promise.resolve(11 as const),
Promise.resolve(12 as const),
Promise.resolve(13 as const),
]);
const l: Array<string | number> = [];
// c infered as Promise<Array<string | number>>
const c = PromiseAll(l);
I meet this issue with V4.0.3, (No overload matchs this call) with different promise types and more than 10 promises
Most helpful comment
A month later: "No overload with more than 150 promises"