diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 64e7ca0a8164a..15f9508c5702b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -31300,6 +31300,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const signature = getContextualSignatureForFunctionLikeDeclaration(functionDecl as FunctionExpression); if (signature && !isResolvingReturnTypeOfSignature(signature)) { const returnType = getReturnTypeOfSignature(signature); + + if (returnType.flags & TypeFlags.Never) { + return returnType; + } + const functionFlags = getFunctionFlags(functionDecl); if (functionFlags & FunctionFlags.Generator) { return filterType(returnType, t => { @@ -31307,9 +31312,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } if (functionFlags & FunctionFlags.Async) { - return filterType(returnType, t => { + const filtered = filterType(returnType, t => { return !!(t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.InstantiableNonPrimitive)) || !!getAwaitedTypeOfPromise(t); }); + return filtered.flags & TypeFlags.Never ? returnType : filtered; } return returnType; } diff --git a/tests/baselines/reference/returnTypeWithGenericAsyncFunction.js b/tests/baselines/reference/returnTypeWithGenericAsyncFunction.js new file mode 100644 index 0000000000000..f336ffb963134 --- /dev/null +++ b/tests/baselines/reference/returnTypeWithGenericAsyncFunction.js @@ -0,0 +1,45 @@ +//// [tests/cases/compiler/returnTypeWithGenericAsyncFunction.ts] //// + +//// [index.ts] +type MockFactoryWithHelper = ( + importOriginal: () => Promise +) => Partial>; +type PromiseMockFactoryWithHelper = ( + importOriginal: () => Promise +) => Promise>>; + +const util: { + mock(module: Promise, factory?: MockFactoryWithHelper): void; + mock(module: Promise, factory?: PromiseMockFactoryWithHelper): void; +} = { + mock: (() => {}) as any, +}; + +util.mock(import("pkg"), async (importOriginal) => ({ + ...(await importOriginal()), +})); + +//// [import.d.ts] +export interface ImportInterface {} +//// [require.d.ts] +export interface RequireInterface {} +//// [package.json] +{ + "name": "pkg", + "version": "0.0.1", + "exports": { + "import": "./import.js", + "require": "./require.js" + } +} + + +//// [index.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const util = { + mock: (() => { }), +}; +util.mock(import("pkg"), async (importOriginal) => ({ + ...(await importOriginal()), +})); diff --git a/tests/baselines/reference/returnTypeWithGenericAsyncFunction.symbols b/tests/baselines/reference/returnTypeWithGenericAsyncFunction.symbols new file mode 100644 index 0000000000000..2ba93de42a3bf --- /dev/null +++ b/tests/baselines/reference/returnTypeWithGenericAsyncFunction.symbols @@ -0,0 +1,87 @@ +//// [tests/cases/compiler/returnTypeWithGenericAsyncFunction.ts] //// + +=== /index.ts === +type MockFactoryWithHelper = ( +>MockFactoryWithHelper : Symbol(MockFactoryWithHelper, Decl(index.ts, 0, 0)) +>M : Symbol(M, Decl(index.ts, 0, 27)) + + importOriginal: () => Promise +>importOriginal : Symbol(importOriginal, Decl(index.ts, 0, 43)) +>T : Symbol(T, Decl(index.ts, 1, 19)) +>M : Symbol(M, Decl(index.ts, 0, 27)) +>M : Symbol(M, Decl(index.ts, 0, 27)) +>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, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>T : Symbol(T, Decl(index.ts, 1, 19)) + +) => Partial>; +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>M : Symbol(M, Decl(index.ts, 0, 27)) + +type PromiseMockFactoryWithHelper = ( +>PromiseMockFactoryWithHelper : Symbol(PromiseMockFactoryWithHelper, Decl(index.ts, 2, 35)) +>M : Symbol(M, Decl(index.ts, 3, 34)) + + importOriginal: () => Promise +>importOriginal : Symbol(importOriginal, Decl(index.ts, 3, 50)) +>T : Symbol(T, Decl(index.ts, 4, 19)) +>M : Symbol(M, Decl(index.ts, 3, 34)) +>M : Symbol(M, Decl(index.ts, 3, 34)) +>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, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>T : Symbol(T, Decl(index.ts, 4, 19)) + +) => Promise>>; +>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, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>M : Symbol(M, Decl(index.ts, 3, 34)) + +const util: { +>util : Symbol(util, Decl(index.ts, 7, 5)) + + mock(module: Promise, factory?: MockFactoryWithHelper): void; +>mock : Symbol(mock, Decl(index.ts, 7, 13), Decl(index.ts, 8, 72)) +>T : Symbol(T, Decl(index.ts, 8, 7)) +>module : Symbol(module, Decl(index.ts, 8, 10)) +>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, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>T : Symbol(T, Decl(index.ts, 8, 7)) +>factory : Symbol(factory, Decl(index.ts, 8, 29)) +>MockFactoryWithHelper : Symbol(MockFactoryWithHelper, Decl(index.ts, 0, 0)) +>T : Symbol(T, Decl(index.ts, 8, 7)) + + mock(module: Promise, factory?: PromiseMockFactoryWithHelper): void; +>mock : Symbol(mock, Decl(index.ts, 7, 13), Decl(index.ts, 8, 72)) +>T : Symbol(T, Decl(index.ts, 9, 7)) +>module : Symbol(module, Decl(index.ts, 9, 10)) +>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, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>T : Symbol(T, Decl(index.ts, 9, 7)) +>factory : Symbol(factory, Decl(index.ts, 9, 29)) +>PromiseMockFactoryWithHelper : Symbol(PromiseMockFactoryWithHelper, Decl(index.ts, 2, 35)) +>T : Symbol(T, Decl(index.ts, 9, 7)) + +} = { + mock: (() => {}) as any, +>mock : Symbol(mock, Decl(index.ts, 10, 5)) + +}; + +util.mock(import("pkg"), async (importOriginal) => ({ +>util.mock : Symbol(mock, Decl(index.ts, 7, 13), Decl(index.ts, 8, 72)) +>util : Symbol(util, Decl(index.ts, 7, 5)) +>mock : Symbol(mock, Decl(index.ts, 7, 13), Decl(index.ts, 8, 72)) +>"pkg" : Symbol("/node_modules/pkg/import", Decl(import.d.ts, 0, 0)) +>importOriginal : Symbol(importOriginal, Decl(index.ts, 14, 32)) + + ...(await importOriginal()), +>importOriginal : Symbol(importOriginal, Decl(index.ts, 14, 32)) + +})); + +=== /node_modules/pkg/import.d.ts === +export interface ImportInterface {} +>ImportInterface : Symbol(ImportInterface, Decl(import.d.ts, 0, 0)) + +=== /node_modules/pkg/require.d.ts === +export interface RequireInterface {} +>RequireInterface : Symbol(RequireInterface, Decl(require.d.ts, 0, 0)) + diff --git a/tests/baselines/reference/returnTypeWithGenericAsyncFunction.types b/tests/baselines/reference/returnTypeWithGenericAsyncFunction.types new file mode 100644 index 0000000000000..7afaf7ab76389 --- /dev/null +++ b/tests/baselines/reference/returnTypeWithGenericAsyncFunction.types @@ -0,0 +1,96 @@ +//// [tests/cases/compiler/returnTypeWithGenericAsyncFunction.ts] //// + +=== /index.ts === +type MockFactoryWithHelper = ( +>MockFactoryWithHelper : MockFactoryWithHelper +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + importOriginal: () => Promise +>importOriginal : () => Promise +> : ^ ^^^^^^^^^ ^^^^^^^^^^^ + +) => Partial>; +type PromiseMockFactoryWithHelper = ( +>PromiseMockFactoryWithHelper : PromiseMockFactoryWithHelper +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + importOriginal: () => Promise +>importOriginal : () => Promise +> : ^ ^^^^^^^^^ ^^^^^^^^^^^ + +) => Promise>>; + +const util: { +>util : { mock(module: Promise, factory?: MockFactoryWithHelper): void; mock(module: Promise, factory?: PromiseMockFactoryWithHelper): void; } +> : ^^^^^^^ ^^ ^^ ^^ ^^^ ^^^ ^^^^^^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ + + mock(module: Promise, factory?: MockFactoryWithHelper): void; +>mock : { (module: Promise, factory?: MockFactoryWithHelper): void; (module: Promise, factory?: PromiseMockFactoryWithHelper): void; } +> : ^^^ ^^ ^^ ^^ ^^^ ^^^ ^^^^^^^^ ^^ ^^ ^^^ ^^^ ^^^ +>module : Promise +> : ^^^^^^^^^^ +>factory : MockFactoryWithHelper +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + mock(module: Promise, factory?: PromiseMockFactoryWithHelper): void; +>mock : { (module: Promise, factory?: MockFactoryWithHelper): void; (module: Promise, factory?: PromiseMockFactoryWithHelper): void; } +> : ^^^^^^^^ ^^ ^^ ^^^ ^^^ ^^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ +>module : Promise +> : ^^^^^^^^^^ +>factory : PromiseMockFactoryWithHelper +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +} = { +>{ mock: (() => {}) as any,} : { mock: any; } +> : ^^^^^^^^ ^^^ + + mock: (() => {}) as any, +>mock : any +>(() => {}) as any : any +>(() => {}) : () => void +> : ^^^^^^^^^^ +>() => {} : () => void +> : ^^^^^^^^^^ + +}; + +util.mock(import("pkg"), async (importOriginal) => ({ +>util.mock(import("pkg"), async (importOriginal) => ({ ...(await importOriginal()),})) : void +> : ^^^^ +>util.mock : { (module: Promise, factory?: MockFactoryWithHelper): void; (module: Promise, factory?: PromiseMockFactoryWithHelper): void; } +> : ^^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ +>util : { mock(module: Promise, factory?: MockFactoryWithHelper): void; mock(module: Promise, factory?: PromiseMockFactoryWithHelper): void; } +> : ^^^^^^^ ^^ ^^ ^^ ^^^ ^^^ ^^^^^^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ +>mock : { (module: Promise, factory?: MockFactoryWithHelper): void; (module: Promise, factory?: PromiseMockFactoryWithHelper): void; } +> : ^^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ ^^ ^^ ^^ ^^^ ^^^ ^^^ +>import("pkg") : Promise<{ default: typeof import("/node_modules/pkg/import"); }> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>"pkg" : "pkg" +> : ^^^^^ +>async (importOriginal) => ({ ...(await importOriginal()),}) : (importOriginal: () => Promise) => Promise<{ default?: any; }> +> : ^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>importOriginal : () => Promise +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>({ ...(await importOriginal()),}) : { default?: any; } +> : ^^^^^^^^^^^^^^^^^^ +>{ ...(await importOriginal()),} : { default?: any; } +> : ^^^^^^^^^^^^^^^^^^ + + ...(await importOriginal()), +>(await importOriginal()) : Partial> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>await importOriginal() : Partial> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>importOriginal() : Promise>> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>importOriginal : () => Promise +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +})); + +=== /node_modules/pkg/import.d.ts === + +export interface ImportInterface {} +=== /node_modules/pkg/require.d.ts === + +export interface RequireInterface {} diff --git a/tests/cases/compiler/returnTypeWithGenericAsyncFunction.ts b/tests/cases/compiler/returnTypeWithGenericAsyncFunction.ts new file mode 100644 index 0000000000000..f78c273f84f30 --- /dev/null +++ b/tests/cases/compiler/returnTypeWithGenericAsyncFunction.ts @@ -0,0 +1,35 @@ +// @module: nodenext +// @target: esnext +// @outDir: out +// @filename: /index.ts +type MockFactoryWithHelper = ( + importOriginal: () => Promise +) => Partial>; +type PromiseMockFactoryWithHelper = ( + importOriginal: () => Promise +) => Promise>>; + +const util: { + mock(module: Promise, factory?: MockFactoryWithHelper): void; + mock(module: Promise, factory?: PromiseMockFactoryWithHelper): void; +} = { + mock: (() => {}) as any, +}; + +util.mock(import("pkg"), async (importOriginal) => ({ + ...(await importOriginal()), +})); + +// @filename: /node_modules/pkg/import.d.ts +export interface ImportInterface {} +// @filename: /node_modules/pkg/require.d.ts +export interface RequireInterface {} +// @filename: /node_modules/pkg/package.json +{ + "name": "pkg", + "version": "0.0.1", + "exports": { + "import": "./import.js", + "require": "./require.js" + } +}