Skip to content

Types for async functions do not handle void assignments like normal ones #33420

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

Open
weswigham opened this issue Sep 13, 2019 · 6 comments
Open
Labels
Bug A bug in TypeScript
Milestone

Comments

@weswigham
Copy link
Member

TypeScript Version: 3.4.0-dev.201xxxxx

Search Terms:

Code

const w: void = "";

const x: () => void = () => "";

const y: () => Promise<void> = async () => "";

function a(): void {
    return "";
}

async function b(): Promise<void> {
    return "";
}

const y2: () => Promise<() => void> =  async () => () => "";

function a2(): () => void {
    return () => "";
}

function b2(): Promise<() => void> {
    return () => "";
}

Expected behavior:
Generally speaking, all of them should be an error, or all of them shouldn't be.

Actual behavior:
We have a special "function returning void" rule that allows () => "" to be assignable to () => void, but this doesn't carry thru to async scenarios, so a async () => "" is not assignable to a () => Promise<void>.

Playground Link

@weswigham weswigham added the Bug A bug in TypeScript label Sep 13, 2019
@weswigham
Copy link
Member Author

There are two rules we have in place governing the above:

  1. void-returning functions should not return non-undefined values.
  2. A function type whose return value is voidis treated as though thatvoidwereunknown`, for the purposes of assignability.

This creates this annoying inconsistency where even though function statement/expressions with annotated returns of void are checked for undefined-ness, consts with function type annotations to which function expressions are assigned are not checked in the same way. Separately, the second rule fails to affect async functions in situations where you'd expect it should, since they don't return void verbatim, but instead return Promise<void>.

@fatcerberus
Copy link

This has caused me pain already when writing typings for miniSphere. Generally speaking I like the rule where a void return acts as any for the purpose of assignment, as it’s useful in HOF scenarios (callbacks e.g.), and it frustrates me that I can’t get the same behavior with async functions.

@fatcerberus
Copy link

fatcerberus commented Sep 14, 2019

This does seem a bit tricky though: if we made the void assignment rule work for Promise<void> would it then end up affecting any generic with a void type argument? I’m not sure whether that’s desirable...

And then even if it is... what about when the type parameter is contravariant? Or invariant? Does variance affect it at all? It’s a pretty big can of worms.

@weswigham
Copy link
Member Author

Tbh, I think void just needs to behave like unknown except we also have lint-level checks to attempt to forbid real-valued returns in implementations whose expected return position type is void.

@fatcerberus
Copy link

I don’t know, I think it’s kind of elegant right now that void is in a duality with any. 😃

  • any: Do whatever you want, I won’t bother you but runtime errors are your problem now
  • void: I’ll put whatever here, don’t try to stop me (by inspecting the value) or else

Where “you” = programmer, “I” = type system.

@Dan503
Copy link

Dan503 commented Oct 19, 2022

I've noticed that void doesn't behave as expected for the following circumstance either:

This should throw an error because () => () => void != () => void

type BasicFn = () => void
// Should throw an error but doesn't
const x: BasicFn  = () => () => console.log('hello')

This bug caused me to spend a multiple hours trying to figure out what I was doing wrong.

It's not easy spotting that () => () => {} should be () => {} especially when you are expecting TS to detect type conflict issues like this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants