-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simplify return type of async function #43303
Comments
Well I don't see how this is worse than #40425 . This does not suggest new syntax to language for no reason. From what I can tell, functions with
is not possible as TS require: You CAN always return Suggestion was closed here #7284 (comment) Main issue is that this requires redundancy on function declaration. Similiar as writing I get argument that This behavior could be optional, maybe this could be discussed again? async fn(): number; // infers Promise<number>
async fn(): boolean | number; // infers Promise<boolean | number>
async fn(): Promise<boolean | number>;
fn(): Promise<number> Some more info: #33595 (comment) async fn(): number { // <-----|
return 3.14; // number <---|
} than this: async fn(): Promise<number> {
return 3.14; // number
} |
Note that you're wrong assuming that every And I personally would find it really confusing if the following would compile:
|
Well technicaly you are right. But this is about async functions that return Promise not about async generators. Still valid point tho.
I agree this is subjective. Looking from inside the functions, types match. Looking from outside, they dont. Nonetheless, this is suggestion as this bugs me in code on deaily basis and I wouldn't be cofused by this. |
This just creates new levels of confusion that are very difficult to reason about, because when you write interface Thenable {
then(): any;
}
async function foo(): Thenable {
return {} as any;
} Does this mean type MyTaggedPromise<T> = Promise<T> & { _isCool?: boolean };
async function bar(): MyTaggedPromise<string> {
// ... Is that a |
Right, and both |
Everytime. Because you have to write that now like that everytime anyway. async function foo(): Thenable => Promise<Thenable>
async function foo(): MyTaggedPromise<string> => Promise<MyTaggedPromise<string>> That is the point, you have to wrap it into |
So let's say that's allowed type Baz = number | Promise<string>;
async function foo(): Baz{
return 0;
} Is this legal, or not? There are strong arguments either way:
|
This is ok in non-async land, but nothing stops you writing My point being: nothing changes. From outside world,
Because with async, I have Promise everytime so there is no 'branching'. Consider current behavior: type Baz = number | Promise<string>;
async function bar(): Promise<Baz> {
const res: Baz = 1;
return res;
}
const a: Baz = await foo(); // error: Type 'string | number' is not assignable to type 'Baz'
const b: Baz = foo(); // error: Type 'Promise<Baz>' is not assignable to type 'Baz'.
interface A {
foo(): Baz;
}
class B implements A {
async foo(): Promise<Baz> { // error: Property 'foo' in type 'B' is not assignable to the same property in base type 'A'.
return 1;
}
} So it looks to me like you can't use this anyway with But if you dont use that strange type and dont try to use it with async function, it is actually smoother from the code point of view. You hide the type Baz = number | string;
async function bar(): Baz {
const res: Baz = 1;
return res;
}
const a: Baz = await foo(); Also both variants would be valid and produce same type: async function bar(): Baz // => Promise<number | string>
async function bar(): Promise<Baz> // Promise<number | string> To me it seems like auto-wrapping is only possible solution. Or is there scenario where auto-wrapping can't be used but can with manual wraping? Also note that |
This is the bug report I'm foreseeing: type Baz = number | Promise<string>;
async function foo(): Baz {
return 0;
} TypeScript failed to catch a bug here; the only legal thing that I can return from this function is a async function foo(): Baz {
return 0 as unknown as Baz;
} and it tells me that "Type |
That is all base on thing that
Current behavior is somehow magic too, and noone questions it: async function foo(): Promise<string> {
// many lines ...
return 'text'; // return type is not Promise<string>
} It is okay just because I used But this fails: function foo(): Promise<string> {
return 'text'; // error: Type 'string' is not assignable to type 'Promise<string>'
} It just bugs me that writing Also, hypoteticaly, if we would introduce function foo(): number throws CustomError
async function foo(): number throws CustomError // => Promise<number, CustomError> |
This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
@RyanCavanaugh I think the async keyword always autowrapping makes sense, and we can achieve your desired maybe async Baz but not using the async keyword. This is identical on how ES async works. maybe sync Baz: type Baz = number | Promise<string>;
function foo(): Baz {
if(sometimes()) {
return 0;
} else {
return Promise.resolve('hello');
}
}
const result = await foo();
// result is 0 or 'hello' Then we can reserve async Baz: type Baz = number | Promise<string>;
async function foo(): Baz {
if(sometimes()) {
return 0;
} else {
return Promise.resolve('hello');
}
}
const result = await foo();
// result is 0 or 'hello' Since Promises collapse, we get 'hello' and not a Promise of 'hello'. |
Suggestion
Allow typing async function without generic Promise type.
π Search Terms
async, promise, return type
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
Async functions always return Promise, so there is no need to specificly write return type of that functions as
Promise<type>
.Combination of async function and simple return type should be enough for typesystem to handle that.
Instead:
This:
Currently results in TS error:
The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<any>'?ts(1064)
So TS clearly knows it MUST be Promise, but requires redundant annotation to prove it.
π» Use Cases
This is particulary useful for projects, which enforces writing down function return types (Angular, ...)
Writing
Promise<X>
is already redundant as just second before you wroteasync
while defining function.Also converting function to async function requires changing return type.
Should be backwards compatible.
Overall my view of typesystem is to add benefit to developer with minimal action. Because of that, we have very good type infering.
This seems to me like handy addition.
And I'm not alone #40425 (comment)
In my head, this doesn't sound too complicated to implement π
The text was updated successfully, but these errors were encountered: