diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ee074403b1b..1c65fb5c076 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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 diff --git a/tests/baselines/reference/asyncFunctionContextuallyTypedReturns.js b/tests/baselines/reference/asyncFunctionContextuallyTypedReturns.js new file mode 100644 index 00000000000..e06a4bde5e4 --- /dev/null +++ b/tests/baselines/reference/asyncFunctionContextuallyTypedReturns.js @@ -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): 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(); })); diff --git a/tests/baselines/reference/asyncFunctionContextuallyTypedReturns.symbols b/tests/baselines/reference/asyncFunctionContextuallyTypedReturns.symbols new file mode 100644 index 00000000000..f3c5847e161 --- /dev/null +++ b/tests/baselines/reference/asyncFunctionContextuallyTypedReturns.symbols @@ -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): 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, --, --)) + diff --git a/tests/baselines/reference/asyncFunctionContextuallyTypedReturns.types b/tests/baselines/reference/asyncFunctionContextuallyTypedReturns.types new file mode 100644 index 00000000000..15a26ac4a9a --- /dev/null +++ b/tests/baselines/reference/asyncFunctionContextuallyTypedReturns.types @@ -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 : (reason?: any) => Promise +>Promise : PromiseConstructor +>reject : (reason?: any) => Promise + +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 : (reason?: any) => Promise +>Promise : PromiseConstructor +>reject : (reason?: any) => Promise + +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 : (reason?: any) => Promise +>Promise : PromiseConstructor +>reject : (reason?: any) => Promise + +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 : (reason?: any) => Promise +>Promise : PromiseConstructor +>reject : (reason?: any) => Promise + +type MyCallback = (thing: string) => void; +>MyCallback : MyCallback +>thing : string + +declare function h(cb: (v: boolean) => MyCallback | PromiseLike): void; +>h : (cb: (v: boolean) => MyCallback | PromiseLike) => void +>cb : (v: boolean) => MyCallback | PromiseLike +>v : boolean + +h(v => v ? (abc) => { } : Promise.reject()); +>h(v => v ? (abc) => { } : Promise.reject()) : void +>h : (cb: (v: boolean) => MyCallback | PromiseLike) => void +>v => v ? (abc) => { } : Promise.reject() : (v: boolean) => ((abc: string) => void) | Promise +>v : boolean +>v ? (abc) => { } : Promise.reject() : ((abc: string) => void) | Promise +>v : boolean +>(abc) => { } : (abc: string) => void +>abc : string +>Promise.reject() : Promise +>Promise.reject : (reason?: any) => Promise +>Promise : PromiseConstructor +>reject : (reason?: any) => Promise + +h(async v => v ? (def) => { } : Promise.reject()); +>h(async v => v ? (def) => { } : Promise.reject()) : void +>h : (cb: (v: boolean) => MyCallback | PromiseLike) => void +>async v => v ? (def) => { } : Promise.reject() : (v: boolean) => Promise void)> +>v : boolean +>v ? (def) => { } : Promise.reject() : Promise | ((def: string) => void) +>v : boolean +>(def) => { } : (def: string) => void +>def : string +>Promise.reject() : Promise +>Promise.reject : (reason?: any) => Promise +>Promise : PromiseConstructor +>reject : (reason?: any) => Promise + diff --git a/tests/cases/compiler/asyncFunctionContextuallyTypedReturns.ts b/tests/cases/compiler/asyncFunctionContextuallyTypedReturns.ts new file mode 100644 index 00000000000..f242b688afe --- /dev/null +++ b/tests/cases/compiler/asyncFunctionContextuallyTypedReturns.ts @@ -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): void; +h(v => v ? (abc) => { } : Promise.reject()); +h(async v => v ? (def) => { } : Promise.reject());