Description
Bug Report
π Search Terms
Nested promises, promise of promise
π Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about nested promises
β― Playground Link
Playground link with relevant code
π» Code
function f1(): Promise<number> {
return Promise.resolve(42);
}
async function f2(): Promise<number> {
return 42;
}
async function f3(): Promise<number> {
return Promise.resolve(42);
}
async function f4(): Promise<Promise<number>> {
const p = Promise.resolve(42);
return Promise.resolve(p);
}
void async function main() {
console.log(await f1());
console.log(await f2());
console.log(await f3());
console.log(await f4());
} ().catch(e => console.error(e));
π Actual behavior
This code compiles without an error or warning. Because JavaScript promises get automatically unwrapped, f1
, f2
, f3
and f4
have essentially the same behavior to the caller, they all return a promise that resolves to a number, which is inconsistent with the return type of f4
, Promise<Promise<number>>
.
π Expected behavior
There should be an error or a warning for f4
, suggesting the type should be Promise<number>
. FWIW, it is impossible to have a promise that resolves to another promise in JavaScript, so nested Promise<Promise<number>>
doesn't make sense and can be misleading.
For example, a person coming from C# (where nested tasks like Task<Task<int>>
is a legit concept), might be tempted to do this in TypeScript:
const outerPromise: Promise<Promise<number>> = f4();
const innerPromise = await outerPromise;
const result = await innerPromise;
This code compiles, but doesn't behave as one may expect. The inferred type for innerPromise
is actually number
, not Promise<number>
.