Home > OS >  How to type an array of Promises of various types in TS?
How to type an array of Promises of various types in TS?

Time:08-24

Given two promises - one that needs to be executed every time and one that needs to be executed only if a condition is met - that I want to execute asynchronously, how do I ensure that return type of Promise.all for each value is correct?

Here's an implementation that I thought should work:

type Promises = [Promise<string>, Promise<number>?]

const promises: Promises = [Promise.resolve('Lorem')]

if (someCondition) {
  promises.push(Promise.resolve(1))
}

// 'resolvedString' should be string
// 'resolvedNumber' should be number | undefined
const [resolvedString, resolvedNumber] = await Promise.all(promises)

but there are two issues with this code:

  • Value of resolvedNumber is number and not number | undefined according to VSCode

  • TS doesn't compile because of following error:

  The last overload gave the following error.
    Argument of type 'Promises' is not assignable to parameter of type 'Iterable<string | PromiseLike<string>>'.
      The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
        Type 'IteratorResult<Promise<string> | Promise<number>, any>' is not assignable to type 'IteratorResult<string | PromiseLike<string>, any>'.
          Type 'IteratorYieldResult<Promise<string> | Promise<number>>' is not assignable to type 'IteratorResult<string | PromiseLike<string>, any>'.
            Type 'IteratorYieldResult<Promise<string> | Promise<number>>' is not assignable to type 'IteratorYieldResult<string | PromiseLike<string>>'.
              Type 'Promise<string> | Promise<number>' is not assignable to type 'string | PromiseLike<string>'.
                Type 'Promise<number>' is not assignable to type 'string | PromiseLike<string>'.
                  Type 'Promise<number>' is not assignable to type 'PromiseLike<string>'.
                    Types of property 'then' are incompatible.
                      Type '<TResult1 = number, TResult2 = never>(onfulfilled?: (value: number) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<...>' is not assignable to type '<TResult1 = string, TResult2 = never>(onfulfilled?: (value: string) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => PromiseLike<...>'.
                        Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible.
                          Types of parameters 'value' and 'value' are incompatible.
                            Type 'number' is not assignable to type 'string'.

93           const [resolvedString, resolvedNumber] = await Promise.all(promises)

TypeScript version is 4.3.5

CodePudding user response:

I don't know if I get the problem right, but, you can basically set several types in your promise, I believe this could help?

Such a type would allow your array to contain several Promises of "different" types. You could eventually Promise.all on this entire array?

const promises: Promise<string | number>[] = [Promise.resolve('Lorem')]
if (someCondition) {
  promises.push(Promise.resolve(1))
}

CodePudding user response:

This is a bug/feature that has been fixed on TS 4.5.

  • Related