typescript - Varför genererar en array med fler än 10 element i Promise.all problemet "No overload matches this call"?


Vänligen överväg följande kod (bara som ett exempel, som den är, för frågans syfte):

class Image {
 protected data: any;
 public static setUp = async (_h: any): Promise<Image> => {
    const me: Image = new Image();
    me.data = await new Promise((resolve) => setTimeout(resolve, 500));
    return me;
 };
}

class Image2 {
 protected data: any;
 public static setUp = async (_h: any): Promise<Image2> => {
    const me: Image2 = new Image2();
    me.data = await new Promise((resolve) => setTimeout(resolve, 500));
    return me;
 };
}
class Image3 {
 protected data: any;
 public static setUp = async (_h: any): Promise<Image3> => {
    const me: Image3 = new Image3();
    me.data = await new Promise((resolve) => setTimeout(resolve, 500));
    return me;
 };
}

async function testing() {
 await Promise.all([
    Image.setUp({}), // 1st
    Image2.setUp({}), // 2nd
    Image3.setUp({}),
    Image3.setUp({}),
    Image3.setUp({}), // 5th
    Image3.setUp({}),
    Image3.setUp({}),
    Image3.setUp({}),
    Image3.setUp({}),
    Image3.setUp({}), //10th
    Image3.setUp({}), // from 11th we will get the following Problem reported
 ]);
}

Problembeskrivningen

No overload matches this call.
  The last overload gave the following error.
    Argument of type '(Promise<Image> | Promise<Image2> | Promise<Image3>)[]' is not assignable to parameter of type 'Iterable<Image | PromiseLike<Image>>'.
      The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
        Type 'IteratorResult<Promise<Image> | Promise<Image2> | Promise<Image3>, any>' is not assignable to type 'IteratorResult<Image | PromiseLike<Image>, any>'.
          Type 'IteratorYieldResult<Promise<Image> | Promise<Image2> | Promise<Image3>>' is not assignable to type 'IteratorResult<Image | PromiseLike<Image>, any>'.
            Type 'IteratorYieldResult<Promise<Image> | Promise<Image2> | Promise<Image3>>' is not assignable to type 'IteratorYieldResult<Image | PromiseLike<Image>>'.
              Type 'Promise<Image> | Promise<Image2> | Promise<Image3>' is not assignable to type 'Image | PromiseLike<Image>'.
                Type 'Promise<Image2>' is not assignable to type 'Image | PromiseLike<Image>'.
                  Type 'Promise<Image2>' is not assignable to type 'PromiseLike<Image>'.
                    Types of property 'then' are incompatible.
                      Type '<TResult1 = Image2, TResult2 = never>(onfulfilled?: ((value: Image2) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | null | undefined) => Promise<...>' is not assignable to type '<TResult1 = Image, TResult2 = never>(onfulfilled?: ((value: Image) => 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 'Image2' is not assignable to type 'Image'.
                              Property 'data' is protected but type 'Image2' is not a class derived from 'Image'.ts(2769)
lib.es2015.iterable.d.ts(226, 5): The last overload is declared here.
(property) Image3.setUp: (_h: any) => Promise<Image3>

Jag har märkt följande:

  • problemet är inte bara relaterat till antalet element i arrayen av Promises utan också till antalet olika typer som returneras, faktiskt kommer det inte att rapportera problemet om en array med längd>10 innehåller Promise som returnerar samma typ
await Promise.all([
        Image3.setUp({}), // 1st
        Image3.setUp({}), // 2nd
        Image3.setUp({}),
        Image3.setUp({}),
        Image3.setUp({}), // 5th
        Image3.setUp({}),
        Image3.setUp({}),
        Image3.setUp({}),
        Image3.setUp({}),
        Image3.setUp({}), //10th
        Image3.setUp({}), // NO ISSUES from here
        Image3.setUp({}),
    ]);

Det verkar som att överbelastningen som definieras för Promise.all i typdefinitionen inte hanterar blandade typer efter en längd på tio element.

En snabb lösning som jag har upptäckt fungerar är att nästla Promise.all på det här sättet

    async function testing() {
    await Promise.all([
        Promise.all([
        Image.setUp({}), // 1st
        Image2.setUp({}), // 2nd
        ]),
        Promise.all([
        Image2.setUp({}), // 3rd
        Image3.setUp({}),
        Image3.setUp({}), // 5th
        Image3.setUp({}),
        Image3.setUp({}),
        Image3.setUp({}),
        Image3.setUp({}),
        Image3.setUp({}), //10th
        Image3.setUp({}),
        ]),
    ]);
    }

Ovanstående kommer att utöka max till 10 element som returnerar blandade typer.

Problemet länkar till den här raden vid gränssnittet PromiseConstructor i lib.es2015.iterable typdefinition:

    all<T>(values: Iterable<T | PromiseLike<T>>): Promise<T[]>;

Jag skulle vilja förstå mer insikten i detta: var misslyckas typdefinitionen? Är det något relaterat till versionen lib.es2015 som löstes i följande versioner? Är det något relaterat till PromiseLike? Varför uppstår problemet från det 11:e elementet?

Svar #1

Detta är en begränsning i hur typen för Promise.all brukade definieras. Inledningsvis kunde TypeScript inte modellera sådana funktioner särskilt väl, så tillvägagångssättet med många överlagringar användes.

Men TypeScript fortsätter att bli bättre hela tiden och nu med förbättringar som rest-tuple-typer, mappade tuple-typer och en mängd prestandaförbättringar, från och med TypeScript 4.5 kommer din kod att fungera utan problem.

Du kan prova TypeScript i lekplatsen eller du kan uppgradera till 4.5 eftersom det redan är tillgängligt på npm

Relaterade artiklar