allow alias async return type promise
Right now if I specify the type of an async function I write foo: () => Promise<string> because that's what it is, fair enough. But it's kind of ugly. The point of async/await is to hide all the ugliness of Promises under syntactic sugar.
TypeScript should do the same and hide the type of the Promise by providing an alternative declaration. Allow us to use the async keyword in type contexts instead of using Promise<?>
So this:
foo: async <T>() => T
could mean the same thing as this:
foo: <T>() => Promise<T>
And would still provide the same IntelliSense as Promise<T>
I've taken into consideration whether it should also allow for T too:
foo: <T>() => Promise<T> | T
My reasoning is that in plain JavaScript awaiting something that's not a Promise just returns that value and TypeScript should respect this.
await "bar"this is valid
This however would completely cripple IntelliSense.
But if it's the case for you, you can always fall back to the <T>() => Promise<T> | T type annotation. (An async? keyword wouldn't really be idiomatic)
My suggestion meets these guidelines:
EDIT: Took out the checks from the guidelines as I discovered some faults in it.
I think this would be really useful and align with the idiomatic JS quite nicely.
Came across a use-case today where I allowed this: foo: (input: T) => Promise<R> | R) because foo is sometimes a read from the file system and sometimes it's just a supplier for a plain string (when I'm unit testing said function for example) And realized that the await keyword doesn't care whether you give it a Promise or not.
I updated the issue with my thoughts on the topic, what do you think?.
With your changes, this becomes related to https://github.com/microsoft/TypeScript/issues/31394
True, but I do think it would be better to use the more strict approach here and infer only Promise<T> from a possible foo: async <T>() => T type implementation.
Again, this is might not as straightforward as it seems. While in purely in terms of types this is rather simple, the actual definition would still be defined as a Promise<T> and changing this would be a breaking change, with probably many more unseen side-effects.
Current:
const foo: <T>(t: T) => Promise<T> = async <T>(t: T): Promise<T> => {
return {} as T;
};
The issue with the idea:
const bar: async <T>(t: T) => T = async <T>(t: T): Promise<T> => {
return {} as T;
};
Only changing the types behavior would lead to some inconsistencies where in the type, async would mean that the return type is wrapped in a Promise while in the actual function definition it's not. This would be really confusing.
For this I think this is not something that would be a welcome change in TypeScript, not even a good one.
I know I went a complete 180掳 here, but I think TypeScript is a great tool for JavaScript and as such it shouldn't mask the actual behavior of it under inconsistent keywords.
I'm leaving this up so someone from the TypeScript team might see this and give a proper opinion about the topic. I might be wrong in the proposal, I might be wrong here.
Because 1) Types are erased at compile time, 2) The proposed async is type-level info only, and 3) The most useful case for this IMO is in declaring the types of functions we don't actually know anything about (e.g., callbacks), the only way this makes sense to me is if it means T | PromiseLike<T>, and in that case we can get exactly the same thing out of the Awaitable<T> type proposed in #31394, without the need for additional syntax.
We went through the same line of thinking when designing the type system functionality for async - forcing you to write Promise<T> is obviously an annoying burden, but it really is the correct thing to do
Most helpful comment
I think this would be really useful and align with the idiomatic JS quite nicely.