TypeScript: Promise> cannot exist in JS
TypeScript Version: Version 3.2.0-dev.20181011
Search Terms: is:open label:Bug promise label:Bug wrapped promise label:Bug wrapped nested
Code
const p1 = new Promise<Promise<Number>>((resolveOuter) => {
const innerPromise = new Promise<Number>((resolveInner) => {
console.log('Resolving inner promise')
resolveInner(1)
})
console.log('Resolving outer promise')
resolveOuter(innerPromise)
})
p1.then((p2: Promise<Number>) => {
p2.then((num) =>
console.log('the number is: ', num)
)
})
Expected behavior:
Compilation should fail, because p1 is actually a Promise<number> due to promise unwrapping.
Actual behavior:
Compilation should fail, requiring code which looks like:
const p1 = new Promise<Number>((resolveOuter) => {
const innerPromise = new Promise<Number>((resolveInner) => {
console.log('Resolving inner promise')
resolveInner(1)
})
console.log('Resolving outer promise')
resolveOuter(innerPromise)
})
p1.then((p2: Number) => {
console.log('the number is: ', p2)
})
Playground Link: Runtime error No runtime error
Related Issues: Didn’t find related issue
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 30
- Comments: 18 (8 by maintainers)
Commits related to this issue
- chore: await axios.request() (err handling fix) Suspicious: return axios.request(deleteRequest); Especially being called towards the _end of the program_ this might result in the HTTP response ... — committed to opstrace/opstrace by jgehrcke 4 years ago
- chore: await axios.request() (err handling fix) Suspicious: return axios.request(deleteRequest); Especially being called towards the _end of the program_ this might result in the HTTP response ... — committed to opstrace/opstrace by jgehrcke 4 years ago
@ORESoftware It does not matter how often you nest a Promise, the result is the same:
This is just how Promises work. You simply cannot get the “inner” Promise, it’s gone, flattened.
I’m not saying that the type
Promise<Promise<T>>is wrong, it might just be the result of a function, wrapping something into a Promise. However, TypeScript should always collapse nested Promises when type checking and compiling because that is what JavaScript does.So now we can do:
The solution would be for
Promisenot to re-wrap if it’s already aPromise. That way, we can never end up with nestedPromises. Here’s a little proof of concept:@DanielRosenwasser @weswigham @rbuckton would this suffice in
lib.es2015.promise.d.ts? It’s a bit unintuitive (the type ofnew Promise<Promise<number>>()would actually evaluate toPromise<number>), but I believe this provides the desired compile-time error.Playground link with some additional testing/assertions 🙂
We have the same problem. We wrap unknown return types into an additional Promise and can get stuck with a resolved type of
Promise<Promise<T>>if the original type was a Promise.This nested Promise however is problematic:
Here,
yis wrongfully seen as aPromise<string>whilezis correctly seen asstring.Why does
awaitandthenbehave differently?Also why can’t we assign a
Promise<Promise<T>>to aPromise<T>variable? This is valid JS since nested Promises always unwrap.So what is the status of this? It is a real deal-braker for function composition. You can’t do any composition of functions that returns promises because you end with
Promise<Promise<Promise<T>>>which doesn’t make any sense in JSawaitedkeyword was in the 4.0 iteration plan (#38510), but 4.0 just released without it.I can’t find any more discussion about it. It’s not in the 4.1 iteration plan (#40124), nor any Design Notes.
I found it being mentioned in #40002, but that pr didn’t actually add the
Awaitedtype into libs right?What’s the current state of this issue?
https://github.com/microsoft/TypeScript/pull/35998#issuecomment-594809232 will make
Promise<Promise<T>>assignable toPromise<T>:I encountered this error when writing a higher-order wrapping function
I have to do
to get
rettypedPromise<string>, but I’d rather not useas