Fix contextual types for maybe-async callbacks (#37205)

* Fix contextual types for maybe-async callbacks

* Remove comment
This commit is contained in:
Wesley Wigham 2020-03-30 14:15:51 -07:00 committed by GitHub
parent 9cd4b070ab
commit 2f0cc51fee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 224 additions and 1 deletions

View File

@ -21810,7 +21810,7 @@ namespace ts {
const contextualReturnType = getContextualReturnType(func);
if (contextualReturnType) {
if (functionFlags & FunctionFlags.Async) { // Async function
const contextualAwaitedType = getAwaitedTypeOfPromise(contextualReturnType);
const contextualAwaitedType = mapType(contextualReturnType, getAwaitedTypeOfPromise);
return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]);
}
return contextualReturnType; // Regular function

View File

@ -0,0 +1,32 @@
//// [asyncFunctionContextuallyTypedReturns.ts]
declare function f(cb: (v: boolean) => [0] | PromiseLike<[0]>): void;
f(v => v ? [0] : Promise.reject());
f(async v => v ? [0] : Promise.reject());
declare function g(cb: (v: boolean) => "contextuallyTypable" | PromiseLike<"contextuallyTypable">): void;
g(v => v ? "contextuallyTypable" : Promise.reject());
g(async v => v ? "contextuallyTypable" : Promise.reject());
type MyCallback = (thing: string) => void;
declare function h(cb: (v: boolean) => MyCallback | PromiseLike<MyCallback>): void;
h(v => v ? (abc) => { } : Promise.reject());
h(async v => v ? (def) => { } : Promise.reject());
//// [asyncFunctionContextuallyTypedReturns.js]
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
f(v => v ? [0] : Promise.reject());
f((v) => __awaiter(void 0, void 0, void 0, function* () { return v ? [0] : Promise.reject(); }));
g(v => v ? "contextuallyTypable" : Promise.reject());
g((v) => __awaiter(void 0, void 0, void 0, function* () { return v ? "contextuallyTypable" : Promise.reject(); }));
h(v => v ? (abc) => { } : Promise.reject());
h((v) => __awaiter(void 0, void 0, void 0, function* () { return v ? (def) => { } : Promise.reject(); }));

View File

@ -0,0 +1,75 @@
=== tests/cases/compiler/asyncFunctionContextuallyTypedReturns.ts ===
declare function f(cb: (v: boolean) => [0] | PromiseLike<[0]>): void;
>f : Symbol(f, Decl(asyncFunctionContextuallyTypedReturns.ts, 0, 0))
>cb : Symbol(cb, Decl(asyncFunctionContextuallyTypedReturns.ts, 0, 19))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 0, 24))
>PromiseLike : Symbol(PromiseLike, Decl(lib.es5.d.ts, --, --))
f(v => v ? [0] : Promise.reject());
>f : Symbol(f, Decl(asyncFunctionContextuallyTypedReturns.ts, 0, 0))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 1, 2))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 1, 2))
>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
f(async v => v ? [0] : Promise.reject());
>f : Symbol(f, Decl(asyncFunctionContextuallyTypedReturns.ts, 0, 0))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 2, 7))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 2, 7))
>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
declare function g(cb: (v: boolean) => "contextuallyTypable" | PromiseLike<"contextuallyTypable">): void;
>g : Symbol(g, Decl(asyncFunctionContextuallyTypedReturns.ts, 2, 41))
>cb : Symbol(cb, Decl(asyncFunctionContextuallyTypedReturns.ts, 4, 19))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 4, 24))
>PromiseLike : Symbol(PromiseLike, Decl(lib.es5.d.ts, --, --))
g(v => v ? "contextuallyTypable" : Promise.reject());
>g : Symbol(g, Decl(asyncFunctionContextuallyTypedReturns.ts, 2, 41))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 5, 2))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 5, 2))
>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
g(async v => v ? "contextuallyTypable" : Promise.reject());
>g : Symbol(g, Decl(asyncFunctionContextuallyTypedReturns.ts, 2, 41))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 6, 7))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 6, 7))
>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
type MyCallback = (thing: string) => void;
>MyCallback : Symbol(MyCallback, Decl(asyncFunctionContextuallyTypedReturns.ts, 6, 59))
>thing : Symbol(thing, Decl(asyncFunctionContextuallyTypedReturns.ts, 8, 19))
declare function h(cb: (v: boolean) => MyCallback | PromiseLike<MyCallback>): void;
>h : Symbol(h, Decl(asyncFunctionContextuallyTypedReturns.ts, 8, 42))
>cb : Symbol(cb, Decl(asyncFunctionContextuallyTypedReturns.ts, 9, 19))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 9, 24))
>MyCallback : Symbol(MyCallback, Decl(asyncFunctionContextuallyTypedReturns.ts, 6, 59))
>PromiseLike : Symbol(PromiseLike, Decl(lib.es5.d.ts, --, --))
>MyCallback : Symbol(MyCallback, Decl(asyncFunctionContextuallyTypedReturns.ts, 6, 59))
h(v => v ? (abc) => { } : Promise.reject());
>h : Symbol(h, Decl(asyncFunctionContextuallyTypedReturns.ts, 8, 42))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 10, 2))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 10, 2))
>abc : Symbol(abc, Decl(asyncFunctionContextuallyTypedReturns.ts, 10, 12))
>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
h(async v => v ? (def) => { } : Promise.reject());
>h : Symbol(h, Decl(asyncFunctionContextuallyTypedReturns.ts, 8, 42))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 11, 7))
>v : Symbol(v, Decl(asyncFunctionContextuallyTypedReturns.ts, 11, 7))
>def : Symbol(def, Decl(asyncFunctionContextuallyTypedReturns.ts, 11, 18))
>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --))

View File

@ -0,0 +1,102 @@
=== tests/cases/compiler/asyncFunctionContextuallyTypedReturns.ts ===
declare function f(cb: (v: boolean) => [0] | PromiseLike<[0]>): void;
>f : (cb: (v: boolean) => [0] | PromiseLike<[0]>) => void
>cb : (v: boolean) => [0] | PromiseLike<[0]>
>v : boolean
f(v => v ? [0] : Promise.reject());
>f(v => v ? [0] : Promise.reject()) : void
>f : (cb: (v: boolean) => [0] | PromiseLike<[0]>) => void
>v => v ? [0] : Promise.reject() : (v: boolean) => [0] | Promise<[0]>
>v : boolean
>v ? [0] : Promise.reject() : [0] | Promise<[0]>
>v : boolean
>[0] : [0]
>0 : 0
>Promise.reject() : Promise<[0]>
>Promise.reject : <T = never>(reason?: any) => Promise<T>
>Promise : PromiseConstructor
>reject : <T = never>(reason?: any) => Promise<T>
f(async v => v ? [0] : Promise.reject());
>f(async v => v ? [0] : Promise.reject()) : void
>f : (cb: (v: boolean) => [0] | PromiseLike<[0]>) => void
>async v => v ? [0] : Promise.reject() : (v: boolean) => Promise<[0] | [0]>
>v : boolean
>v ? [0] : Promise.reject() : [0] | Promise<[0]>
>v : boolean
>[0] : [0]
>0 : 0
>Promise.reject() : Promise<[0]>
>Promise.reject : <T = never>(reason?: any) => Promise<T>
>Promise : PromiseConstructor
>reject : <T = never>(reason?: any) => Promise<T>
declare function g(cb: (v: boolean) => "contextuallyTypable" | PromiseLike<"contextuallyTypable">): void;
>g : (cb: (v: boolean) => "contextuallyTypable" | PromiseLike<"contextuallyTypable">) => void
>cb : (v: boolean) => "contextuallyTypable" | PromiseLike<"contextuallyTypable">
>v : boolean
g(v => v ? "contextuallyTypable" : Promise.reject());
>g(v => v ? "contextuallyTypable" : Promise.reject()) : void
>g : (cb: (v: boolean) => "contextuallyTypable" | PromiseLike<"contextuallyTypable">) => void
>v => v ? "contextuallyTypable" : Promise.reject() : (v: boolean) => "contextuallyTypable" | Promise<"contextuallyTypable">
>v : boolean
>v ? "contextuallyTypable" : Promise.reject() : "contextuallyTypable" | Promise<"contextuallyTypable">
>v : boolean
>"contextuallyTypable" : "contextuallyTypable"
>Promise.reject() : Promise<"contextuallyTypable">
>Promise.reject : <T = never>(reason?: any) => Promise<T>
>Promise : PromiseConstructor
>reject : <T = never>(reason?: any) => Promise<T>
g(async v => v ? "contextuallyTypable" : Promise.reject());
>g(async v => v ? "contextuallyTypable" : Promise.reject()) : void
>g : (cb: (v: boolean) => "contextuallyTypable" | PromiseLike<"contextuallyTypable">) => void
>async v => v ? "contextuallyTypable" : Promise.reject() : (v: boolean) => Promise<"contextuallyTypable">
>v : boolean
>v ? "contextuallyTypable" : Promise.reject() : "contextuallyTypable" | Promise<"contextuallyTypable">
>v : boolean
>"contextuallyTypable" : "contextuallyTypable"
>Promise.reject() : Promise<"contextuallyTypable">
>Promise.reject : <T = never>(reason?: any) => Promise<T>
>Promise : PromiseConstructor
>reject : <T = never>(reason?: any) => Promise<T>
type MyCallback = (thing: string) => void;
>MyCallback : MyCallback
>thing : string
declare function h(cb: (v: boolean) => MyCallback | PromiseLike<MyCallback>): void;
>h : (cb: (v: boolean) => MyCallback | PromiseLike<MyCallback>) => void
>cb : (v: boolean) => MyCallback | PromiseLike<MyCallback>
>v : boolean
h(v => v ? (abc) => { } : Promise.reject());
>h(v => v ? (abc) => { } : Promise.reject()) : void
>h : (cb: (v: boolean) => MyCallback | PromiseLike<MyCallback>) => void
>v => v ? (abc) => { } : Promise.reject() : (v: boolean) => ((abc: string) => void) | Promise<MyCallback>
>v : boolean
>v ? (abc) => { } : Promise.reject() : ((abc: string) => void) | Promise<MyCallback>
>v : boolean
>(abc) => { } : (abc: string) => void
>abc : string
>Promise.reject() : Promise<MyCallback>
>Promise.reject : <T = never>(reason?: any) => Promise<T>
>Promise : PromiseConstructor
>reject : <T = never>(reason?: any) => Promise<T>
h(async v => v ? (def) => { } : Promise.reject());
>h(async v => v ? (def) => { } : Promise.reject()) : void
>h : (cb: (v: boolean) => MyCallback | PromiseLike<MyCallback>) => void
>async v => v ? (def) => { } : Promise.reject() : (v: boolean) => Promise<MyCallback | ((def: string) => void)>
>v : boolean
>v ? (def) => { } : Promise.reject() : Promise<MyCallback> | ((def: string) => void)
>v : boolean
>(def) => { } : (def: string) => void
>def : string
>Promise.reject() : Promise<MyCallback>
>Promise.reject : <T = never>(reason?: any) => Promise<T>
>Promise : PromiseConstructor
>reject : <T = never>(reason?: any) => Promise<T>

View File

@ -0,0 +1,14 @@
// @target: es6
// @strict: true
declare function f(cb: (v: boolean) => [0] | PromiseLike<[0]>): void;
f(v => v ? [0] : Promise.reject());
f(async v => v ? [0] : Promise.reject());
declare function g(cb: (v: boolean) => "contextuallyTypable" | PromiseLike<"contextuallyTypable">): void;
g(v => v ? "contextuallyTypable" : Promise.reject());
g(async v => v ? "contextuallyTypable" : Promise.reject());
type MyCallback = (thing: string) => void;
declare function h(cb: (v: boolean) => MyCallback | PromiseLike<MyCallback>): void;
h(v => v ? (abc) => { } : Promise.reject());
h(async v => v ? (def) => { } : Promise.reject());