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?
- Use
as const
when usingPromise.resolve()
.
const [a1] = await Promise.all([Promise.resolve('test' as const)])
// ^? a1: "test"
- 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"
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);
})();