Home > database >  Typescript doesn't infer types for Promise.all()
Typescript doesn't infer types for Promise.all()

Time:06-26

Please explain someone the reason and mechanics of that TS doesn't match the types for a (string vs 'test') matching those for b at the same time. How can I solve this? The playground is here. Thank you in advance.

(async () => {
    const [a]: ['test'] = await Promise.all([Promise.resolve('test')])
    //     ^ type mismatch here
    const b: 'test' = await Promise.resolve('test')
    console.log(a, b)
})()

CodePudding user response:

The issue here seems to be the implementation of the Promise.resolve() function. Whoever implemented the typing did not want types to be inferred as narrow as they could be.

const c = await Promise.resolve("test")
//    ^? c: string

As you can see, when calling Promise.resolve() with a string literal, the type is widened to string.

Interestingly, this does not happen when giving an explicit type to the variable.

const d: "test" = await Promise.resolve("test")
//    ^? d: "test"

This behaviour seemed to change in version 3.5 but I am still looking for the changelog which explains this feature.


So what are your options?

  1. Use as const when using Promise.resolve().
const [a1] = await Promise.all([Promise.resolve('test' as const)])
//     ^? a1: "test"
  1. You could write your own wrapper function for Promise.resolve() which respects narrow types.
type Every =
  | null
  | string
  | number
  | boolean
  | Array<Every>
  | object
  | symbol
  | undefined
  | {
      [prop: string]: Every
    }

function PromiseResolve<T extends Every>(p: T): Promise<T> {
  return Promise.resolve(p)
}


const [a2] = await Promise.all([PromiseResolve('test')])
//     ^? a2: "test"

Playground

CodePudding user response:

it won't materialize unless it's casted as a constant. const on it's own like this is just a string.

(async () => {
  const str = <const>"test";
  const [a] = await Promise.all([Promise.resolve(str)]);
  const b = await Promise.resolve(str);
  console.log(a, b);
})();
  • Related