Skip to content

async function drops Awaited<Type> #56083

Open
@ondrej-stanek-ozobot

Description

@ondrej-stanek-ozobot

🔎 Search Terms

async function drops Awaited
Awaited swallowed in async
Awaited removed

🕗 Version & Regression Information

  • This is the behavior in every TS version I tried, started occurring since TS v 4.5.5 when the Awaited was introduced.

⏯ Playground Link

https://www.typescriptlang.org/play?ts=4.5.5#code/PTAEGcEsHMDsEMAuBXATgU3KA9gM1IgBbqi7KwDGik2sW8GoF2ADpOgCamrYC2oABR69I4dADpU8CugBQsspWq1QUmQH1IHdLGqIAnuuwBrADwAVUOgAeiHRywZ4HWgBt9ocsdjYA7rABtAF1QAB9QYIA+AApQADd4V2RMAC5QcwBKNKE+UXRTAEFfeEg7DgsA2GReACN0VCDIyNAAb1lQDtV0FFRYQWE8yWl0aISkzAyOkFAAeQBpABpQLR09D0UqGj7fbFRjLAArZHBEUkhYOQBfeQ3lPrV0dV8pFhZOTVh1eHB9SnUfRBGMyWGx2WAOLrONweLw+fzBMIRRqxMbJcBpTLZAZiQrFUqcCpVWr1RrNNqdJi0E6gb6-CgAdReb1QoAAvDSfpRQNFJqyye0KZ1mHRTg82TS8acciIxEMZKNEmiMgLBaBpsLqQ80kUSmVCdU6g1moL5ksiKICPo3sssDY3lROCrBRgevdhhSndcKeqqadaZRGfBXvU0jy2c1pXl9cSjYLzVgLQDZotQE7pr4SHb0FRLdaw3z+rkcTr8eVzJUDSSmksashTkQSAADEt6yKN0DFLAcHjBjhLZmEIPgAD88gpLrQfX9DKZ9R5abA9R4qBSC-SVpIAHJIzjy0TDY1NzbQEnvlA4PAaq4SIhsLmtzv8i2CXvK0bIpvxGvzBvQJvXzGQRHom2B+uA54IFeN53gY1qbs+ZYVoBH7iNEABMADMaFocqlxAA

💻 Code

// signatures of the functions are copied from Promise.race

function race_identity_ok<T extends readonly unknown[] | []>( values: T): Promise<Awaited<T[number]>> {
    return Promise.race(values)  // OK, identity function works just fine
}

function race_wrapped_in_async_not_ok<T extends readonly unknown[] | []>( values: T): Promise<Awaited<T[number]>> {
    const asyncWrapper = async () => {
        const race = await Promise.race(values)
        // const race: Awaited<T[number]>      OK, this type is expected
        return race    
    }
    // const asyncWrapper: () => Promise<T[number]>     this is not OK, 
    // we expect type () => Promise<Awaited<T[number]>>, but the `Awaited<>` was dropped, perhaps?

    return asyncWrapper()
    // error:
    // Type 'Promise<T[number]>' is not assignable to type 'Promise<Awaited<T[number]>>'.
    // Type 'T[number]' is not assignable to type 'Awaited<T[number]>'.(2322)
}```


### 🙁 Actual behavior

The `Awaited<Type>` is dropped from the return type of the function `asyncWrapper`, but it should not be (at least as I can tell).


### 🙂 Expected behavior

The `Awaited` should not be dropped.
I believe so because I assume the `Awaited` in the `Promise.race` signature is of crucial importance, as it denotes that if type `T` is a thenable (or `PromiseLike`, if you like), it is unwrapped in the return type.
Wrapping the `Promise.race` in `async` function (`asyncWrapper`) looses the unwrapping semantics, in my opinion.



### Additional information about the issue

The issue might seem artificial, however, this is the minimalist example I came up with. In our codebase, the issue is convoluted because we replace `PromiseLike` with [CancellablePromise](https://github.com/srmagura/real-cancellable-promise). We need the async function wrapper to correctly deduce return type (and keep the `Awaited`), so that the return type of `Promise.race` is perserved when fed through the [buildCancellablePromise](https://github.com/srmagura/real-cancellable-promise#combine-multiple-api-calls-into-a-single-async-flow).

Metadata

Metadata

Assignees

Labels

Needs InvestigationThis issue needs a team member to investigate its status.

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions