diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6c0e83eb339b0..f5b3001717809 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4865,19 +4865,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions); const resolvedModule = getResolvedModule(currentSourceFile, moduleReference, mode); const resolutionDiagnostic = resolvedModule && getResolutionDiagnostic(compilerOptions, resolvedModule, currentSourceFile); - const sourceFile = resolvedModule + const targetSourceFile = resolvedModule && (!resolutionDiagnostic || resolutionDiagnostic === Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set) && host.getSourceFile(resolvedModule.resolvedFileName); - if (sourceFile) { + if (targetSourceFile) { // If there's a resolutionDiagnostic we need to report it even if a sourceFile is found. if (resolutionDiagnostic) { error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName); } + const importOrExport = + findAncestor(location, isImportDeclaration)?.importClause || + findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)); if (resolvedModule.resolvedUsingTsExtension && isDeclarationFileName(moduleReference)) { - const importOrExport = - findAncestor(location, isImportDeclaration)?.importClause || - findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)); if (importOrExport && !importOrExport.isTypeOnly || findAncestor(location, isImportCall)) { error( errorNode, @@ -4890,17 +4890,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(errorNode, Diagnostics.An_import_path_can_only_end_with_a_0_extension_when_allowImportingTsExtensions_is_enabled, tsExtension); } - if (sourceFile.symbol) { + if (targetSourceFile.symbol) { if (resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) { errorOnImplicitAnyModule(/*isError*/ false, errorNode, currentSourceFile, mode, resolvedModule, moduleReference); } - if (moduleResolutionKind === ModuleResolutionKind.Node16 || moduleResolutionKind === ModuleResolutionKind.NodeNext) { + if (ModuleResolutionKind.Node16 <= moduleResolutionKind && moduleResolutionKind <= ModuleResolutionKind.NodeNext && !importOrExport?.isTypeOnly && !findAncestor(location, isImportTypeNode)) { const isSyncImport = (currentSourceFile.impliedNodeFormat === ModuleKind.CommonJS && !findAncestor(location, isImportCall)) || !!findAncestor(location, isImportEqualsDeclaration); - const overrideClauseHost = findAncestor(location, l => isImportTypeNode(l) || isExportDeclaration(l) || isImportDeclaration(l)) as ImportTypeNode | ImportDeclaration | ExportDeclaration | undefined; - const overrideClause = overrideClauseHost && isImportTypeNode(overrideClauseHost) ? overrideClauseHost.assertions?.assertClause : overrideClauseHost?.assertClause; - // An override clause will take effect for type-only imports and import types, and allows importing the types across formats, regardless of - // normal mode restrictions - if (isSyncImport && sourceFile.impliedNodeFormat === ModuleKind.ESNext && !getResolutionModeOverrideForClause(overrideClause)) { + if (isSyncImport && targetSourceFile.impliedNodeFormat === ModuleKind.ESNext) { if (findAncestor(location, isImportEqualsDeclaration)) { // ImportEquals in a ESM file resolving to another ESM file error(errorNode, Diagnostics.Module_0_cannot_be_imported_using_this_construct_The_specifier_only_resolves_to_an_ES_module_which_cannot_be_imported_with_require_Use_an_ECMAScript_import_instead, moduleReference); @@ -4949,11 +4945,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } // merged symbol is module declaration symbol combined with all augmentations - return getMergedSymbol(sourceFile.symbol); + return getMergedSymbol(targetSourceFile.symbol); } if (moduleNotFoundError) { // report errors only if it was requested - error(errorNode, Diagnostics.File_0_is_not_a_module, sourceFile.fileName); + error(errorNode, Diagnostics.File_0_is_not_a_module, targetSourceFile.fileName); } return undefined; } diff --git a/tests/baselines/reference/importTypeResolvingToESMFromCJS.js b/tests/baselines/reference/importTypeResolvingToESMFromCJS.js new file mode 100644 index 0000000000000..5f16a2bfe6fa2 --- /dev/null +++ b/tests/baselines/reference/importTypeResolvingToESMFromCJS.js @@ -0,0 +1,12 @@ +//// [tests/cases/compiler/importTypeResolvingToESMFromCJS.ts] //// + +//// [types.d.mts] +export interface A {} + +//// [main.cts] +type A = import("./types.mjs").A; + + +//// [main.cjs] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/tests/baselines/reference/importTypeResolvingToESMFromCJS.symbols b/tests/baselines/reference/importTypeResolvingToESMFromCJS.symbols new file mode 100644 index 0000000000000..6a75af6ab1c39 --- /dev/null +++ b/tests/baselines/reference/importTypeResolvingToESMFromCJS.symbols @@ -0,0 +1,9 @@ +=== /types.d.mts === +export interface A {} +>A : Symbol(A, Decl(types.d.mts, 0, 0)) + +=== /main.cts === +type A = import("./types.mjs").A; +>A : Symbol(A, Decl(main.cts, 0, 0)) +>A : Symbol(A, Decl(types.d.mts, 0, 0)) + diff --git a/tests/baselines/reference/importTypeResolvingToESMFromCJS.types b/tests/baselines/reference/importTypeResolvingToESMFromCJS.types new file mode 100644 index 0000000000000..ec12e8e19605c --- /dev/null +++ b/tests/baselines/reference/importTypeResolvingToESMFromCJS.types @@ -0,0 +1,8 @@ +=== /types.d.mts === + +export interface A {} + +=== /main.cts === +type A = import("./types.mjs").A; +>A : import("/types", { assert: { "resolution-mode": "import" } }).A + diff --git a/tests/baselines/reference/tsbuildWatch/moduleResolution/resolves-specifier-in-output-declaration-file-from-referenced-project-correctly-with-cts-and-mts-extensions.js b/tests/baselines/reference/tsbuildWatch/moduleResolution/resolves-specifier-in-output-declaration-file-from-referenced-project-correctly-with-cts-and-mts-extensions.js index 76dda26edbea1..c6f15130f578d 100644 --- a/tests/baselines/reference/tsbuildWatch/moduleResolution/resolves-specifier-in-output-declaration-file-from-referenced-project-correctly-with-cts-and-mts-extensions.js +++ b/tests/baselines/reference/tsbuildWatch/moduleResolution/resolves-specifier-in-output-declaration-file-from-referenced-project-correctly-with-cts-and-mts-extensions.js @@ -338,13 +338,7 @@ File '/user/username/projects/myproject/packages/pkg2/build/const.d.cts' exists File '/a/lib/package.json' does not exist. File '/a/package.json' does not exist. File '/package.json' does not exist. -packages/pkg1/index.ts:1:29 - error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("pkg2")' call instead. - To convert this file to an ECMAScript module, change its file extension to '.mts' or create a local package.json file with `{ "type": "module" }`. - -1 import type { TheNum } from 'pkg2' -   ~~~~~~ - -[12:01:16 AM] Found 1 error. Watching for file changes. +[12:01:20 AM] Found 0 errors. Watching for file changes. @@ -365,6 +359,13 @@ Shape signatures in builder refreshed for:: exitCode:: ExitStatus.undefined +//// [/user/username/projects/myproject/packages/pkg1/build/index.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.theNum = void 0; +exports.theNum = 42; + + Change:: removes those errors when a package file is changed back @@ -375,11 +376,11 @@ Input:: Output:: >> Screen clear -[12:01:20 AM] File change detected. Starting incremental compilation... +[12:01:24 AM] File change detected. Starting incremental compilation... -[12:01:21 AM] Project 'packages/pkg1/tsconfig.json' is out of date because output 'packages/pkg1/build/index.js' is older than input 'packages/pkg1/package.json' +[12:01:25 AM] Project 'packages/pkg1/tsconfig.json' is out of date because output 'packages/pkg1/build/index.js' is older than input 'packages/pkg1/package.json' -[12:01:22 AM] Building project '/user/username/projects/myproject/packages/pkg1/tsconfig.json'... +[12:01:26 AM] Building project '/user/username/projects/myproject/packages/pkg1/tsconfig.json'... Found 'package.json' at '/user/username/projects/myproject/packages/pkg1/package.json'. ======== Resolving module 'pkg2' from '/user/username/projects/myproject/packages/pkg1/index.ts'. ======== @@ -417,7 +418,7 @@ File '/user/username/projects/myproject/packages/pkg2/build/const.d.cts' exists File '/a/lib/package.json' does not exist. File '/a/package.json' does not exist. File '/package.json' does not exist. -[12:01:27 AM] Found 0 errors. Watching for file changes. +[12:01:31 AM] Found 0 errors. Watching for file changes. @@ -438,7 +439,10 @@ Shape signatures in builder refreshed for:: exitCode:: ExitStatus.undefined -//// [/user/username/projects/myproject/packages/pkg1/build/index.js] file written with same contents +//// [/user/username/projects/myproject/packages/pkg1/build/index.js] +export const theNum = 42; + + Change:: reports import errors after change to package file @@ -449,11 +453,11 @@ Input:: Output:: >> Screen clear -[12:01:31 AM] File change detected. Starting incremental compilation... +[12:01:35 AM] File change detected. Starting incremental compilation... -[12:01:32 AM] Project 'packages/pkg1/tsconfig.json' is out of date because output 'packages/pkg1/build/index.js' is older than input 'packages/pkg1/package.json' +[12:01:36 AM] Project 'packages/pkg1/tsconfig.json' is out of date because output 'packages/pkg1/build/index.js' is older than input 'packages/pkg1/package.json' -[12:01:33 AM] Building project '/user/username/projects/myproject/packages/pkg1/tsconfig.json'... +[12:01:37 AM] Building project '/user/username/projects/myproject/packages/pkg1/tsconfig.json'... Found 'package.json' at '/user/username/projects/myproject/packages/pkg1/package.json'. ======== Resolving module 'pkg2' from '/user/username/projects/myproject/packages/pkg1/index.ts'. ======== @@ -494,13 +498,7 @@ File '/user/username/projects/myproject/packages/pkg2/build/const.d.cts' exists File '/a/lib/package.json' does not exist. File '/a/package.json' does not exist. File '/package.json' does not exist. -packages/pkg1/index.ts:1:29 - error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("pkg2")' call instead. - To convert this file to an ECMAScript module, change its file extension to '.mts' or create a local package.json file with `{ "type": "module" }`. - -1 import type { TheNum } from 'pkg2' -   ~~~~~~ - -[12:01:34 AM] Found 1 error. Watching for file changes. +[12:01:42 AM] Found 0 errors. Watching for file changes. @@ -521,6 +519,13 @@ Shape signatures in builder refreshed for:: exitCode:: ExitStatus.undefined +//// [/user/username/projects/myproject/packages/pkg1/build/index.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.theNum = void 0; +exports.theNum = 42; + + Change:: removes those errors when a package file is changed to cjs extensions @@ -535,11 +540,11 @@ export type { TheNum } from './const.cjs'; Output:: >> Screen clear -[12:01:42 AM] File change detected. Starting incremental compilation... +[12:01:50 AM] File change detected. Starting incremental compilation... -[12:01:43 AM] Project 'packages/pkg2/tsconfig.json' is out of date because output 'packages/pkg2/build/tsconfig.tsbuildinfo' is older than input 'packages/pkg2/index.cts' +[12:01:51 AM] Project 'packages/pkg2/tsconfig.json' is out of date because output 'packages/pkg2/build/tsconfig.tsbuildinfo' is older than input 'packages/pkg2/index.cts' -[12:01:44 AM] Building project '/user/username/projects/myproject/packages/pkg2/tsconfig.json'... +[12:01:52 AM] Building project '/user/username/projects/myproject/packages/pkg2/tsconfig.json'... ======== Resolving module './const.cjs' from '/user/username/projects/myproject/packages/pkg2/index.cts'. ======== Module resolution kind is not specified, using 'Node16'. @@ -551,9 +556,9 @@ File '/user/username/projects/myproject/packages/pkg2/const.cts' exists - use it File '/a/lib/package.json' does not exist. File '/a/package.json' does not exist. File '/package.json' does not exist. -[12:01:56 AM] Project 'packages/pkg1/tsconfig.json' is out of date because output 'packages/pkg1/build/index.js' is older than input 'packages/pkg2' +[12:02:04 AM] Project 'packages/pkg1/tsconfig.json' is out of date because output 'packages/pkg1/build/index.js' is older than input 'packages/pkg2' -[12:01:57 AM] Building project '/user/username/projects/myproject/packages/pkg1/tsconfig.json'... +[12:02:05 AM] Building project '/user/username/projects/myproject/packages/pkg1/tsconfig.json'... Found 'package.json' at '/user/username/projects/myproject/packages/pkg1/package.json'. ======== Resolving module 'pkg2' from '/user/username/projects/myproject/packages/pkg1/index.ts'. ======== @@ -591,7 +596,7 @@ File '/user/username/projects/myproject/packages/pkg2/build/const.d.cts' exists File '/a/lib/package.json' does not exist according to earlier cached lookups. File '/a/package.json' does not exist according to earlier cached lookups. File '/package.json' does not exist according to earlier cached lookups. -[12:02:02 AM] Found 0 errors. Watching for file changes. +[12:02:10 AM] Found 0 errors. Watching for file changes. @@ -749,13 +754,7 @@ exitCode:: ExitStatus.undefined "size": 1064 } -//// [/user/username/projects/myproject/packages/pkg1/build/index.js] -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.theNum = void 0; -exports.theNum = 42; - - +//// [/user/username/projects/myproject/packages/pkg1/build/index.js] file written with same contents //// [/user/username/projects/myproject/packages/pkg2/build/index.cjs] "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/tests/cases/compiler/importTypeResolvingToESMFromCJS.ts b/tests/cases/compiler/importTypeResolvingToESMFromCJS.ts new file mode 100644 index 0000000000000..20056efc62627 --- /dev/null +++ b/tests/cases/compiler/importTypeResolvingToESMFromCJS.ts @@ -0,0 +1,7 @@ +// @module: nodenext + +// @Filename: /types.d.mts +export interface A {} + +// @Filename: /main.cts +type A = import("./types.mjs").A;