Repository: TypeScript
Issue: Promise<non-void> not assignable to Promise<void> w/fn return type
Labels: Needs Investigation

# Bug Report

### 🔎 Search Terms
promise void assignable 2345

### 🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about ["Why are functions returning non-void assignable to function returning void?"](https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-functions-returning-non-void-assignable-to-function-returning-void) and Issue #4544

### ⏯ Playground Link
[Playground link with relevant code](https://www.typescriptlang.org/play?#code/PTDKFMBcAIEYC5oHUD2AnA1gZ2gMwJYB24ANNAIY7gAeADuAMaTgAmAUAyoVjJORuCwA1FPhYAlKAFc0hIgHMAYlMJN8XaAF48KtVwAUPcmmZpE+8qEhnoPNAoCUWgHzQAbqJZOA3sABUAHRBfsAAvhxcPO6ekpAycoRKupDqhFo6qikGltaIdo7QiB5i0N5o0rIA3OGc3DAARigoADax8QrKmanpuMmpFlY2+YlOiI0t4ORpZRVp1lLg1Wx8AsIxsx19BsUSG4mdeoQOlcv8giJibbKbXQbjrXtJt0cnbCAQMABMiAAqABbgChYACeqnc4DQWG6KFwtigcAidWgK3O6zi10SAEEQaoDlk0tpes9DHwTBDzDkhtYCppXAAFNAoAC2+Cw4AAPDtnD5-EEAiEapEYDsrgl5NjQQw8d1tJRJRlDgNcrZqSNCtAGczWRyuaVyujCEtalF7qKFBLcVsCUD5UTFZS8qr5KMNYyWWz2fdJoRXDMDci0Aslii1pdHhapVb9CLwzjI89jqdVhddgbzXHpXcmg801iM1bjtAQABRNCMtDQAHleBvYCYtDyKRM8CEGAw5HA+jQADk+ictNdWo9Xqmzm70FZ0EIKBglCh8kI5HqzUBkBQ0FoxnIzdM0HbkE7gN7-fpbu1nM8Y4Cteg0B+h57mvdHJHPvHk+ns6w88Xy9X64PLtuyfc8uW7a8QFvW97yA193xwT8gR-JcV2RACH27HZwMgLB9E+ABmAAWABWBw2FrD5oHwxBMVsfAmVoFcKzcCEoQ0ds2S+REohDFNJCwFo3AUEC2R6KMjDJGwRJ1S8fDYABICTTACSAAUIfQ7XxPtSl5YIwkTQUkRjATmiExJpPSaSAnKEyWL7E5jQabN+ME4Sz1E7QrJswTwH0eZwETXj1lstyh184zXPM9yApOIKwxCqKwv0U1BEi+RpMLEsy3QSsIXAGsQHrRtm1bPdYUAo9pM9bNvTHCcEJnJD8AXFD-w3LcdwhMqOyAqqwIg4BoIwuD6qnRq52a39ULXHqjywlTcIIkiyKAA)

### 💻 Code
```ts
//Set 1: Works fine, as expected
const takesVoidReturningFunction = function(starter: (aStr: string) => void) {/*...*/}
const voidReturningFunction = function(aStr: string) : void {return;}
const boolReturningFunction = function(aStr: string) : boolean {return true;}
takesVoidReturningFunction(voidReturningFunction);
takesVoidReturningFunction(boolReturningFunction);

//Set 2: The async version of set 1
const takesVoidReturningAsyncFunction = function(starter: (aStr: string) => Promise<void>) {/*...*/}
const voidReturningAsyncFunction = async function(aStr: string) : Promise<void> {return;}
const boolReturningAsyncFunction = async function(aStr: string) : Promise<boolean> {return true;}
takesVoidReturningAsyncFunction(voidReturningAsyncFunction);
takesVoidReturningAsyncFunction(boolReturningAsyncFunction); //Error here:
//Argument of type '() => Promise<boolean>' is not assignable to parameter of type '() => Promise<void>'.
//  Type 'Promise<boolean>' is not assignable to type 'Promise<void>'.
//    Type 'boolean' is not assignable to type 'void'.ts(2345)

//Set 3: A simpler version of set 2
const takesVoidResolvingPromise = function(starter: Promise<void>) {
	starter.then(function() {/*...*/});
}
const voidResolvingPromise = Promise.resolve();
const boolResolvingPromise = Promise.resolve(true);
takesVoidResolvingPromise(voidResolvingPromise);
takesVoidResolvingPromise(boolResolvingPromise); //Error here:
//Argument of type 'Promise<boolean>' is not assignable to parameter of type 'Promise<void>'.
//  Type 'boolean' is not assignable to type 'void'.ts(2345)
```

### 🙁 Actual behavior
Errors as noted in code comments.

### 🙂 Expected behavior
Async functions that resolve non-void are assignable to async function types that resolve void, just like synchronous functions that return non-void are assignable to synchronous function types that return void.

The string parameter is given in the example code to maintain the idea that the function may have desirable side effects and thus be worth calling, even if the resolve value isn't relevant to the calling context.

The [FAQ states](https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-functions-returning-non-void-assignable-to-function-returning-void) (with only example function names changed) that 
>functions returning non-void assignable to function returning void...is the expected and desired behavior. First, refer to the "substitutability" primer -- the fact that `boolReturningFunction` returns "more" information than `voidReturningFunction` is a valid substitution...Another way to think of this is that a void-returning callback type says "I'm not going to look at your return value, if one exists".

Why isn't the same true of async functions?
It's pretty annoying to have to write a wrapper function around every async function just to have a void-resolving function that the TypeScript compiler demands, as another example of valid JavaScript that has to be rewritten with more than just type annotations in a conversion.