diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 390c843b0c968..5d446f6799418 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3794,6 +3794,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // are ESM, there cannot be a synthetic default. return false; } + // For other files (not node16/nodenext with impliedNodeFormat), check if we can determine + // the module format from project references + if (!targetMode && file.isDeclarationFile) { + // Try to get the project reference - try both source file mapping and output file mapping + // since declaration files can be mapped either way depending on how they're resolved + const redirect = host.getRedirectFromSourceFile(file.path) || host.getRedirectFromOutput(file.path); + if (redirect) { + // This is a declaration file from a project reference, so we can determine + // its module format from the referenced project's options + const targetModuleKind = host.getEmitModuleFormatOfFile(file); + if (usageMode === ModuleKind.ESNext && ModuleKind.ES2015 <= targetModuleKind && targetModuleKind <= ModuleKind.ESNext) { + return false; + } + } + } } if (!allowSyntheticDefaultImports) { return false; diff --git a/src/testRunner/unittests/tsc/projectReferences.ts b/src/testRunner/unittests/tsc/projectReferences.ts index 3a5b1e09de7ad..9e1460e6ff6a6 100644 --- a/src/testRunner/unittests/tsc/projectReferences.ts +++ b/src/testRunner/unittests/tsc/projectReferences.ts @@ -90,6 +90,35 @@ describe("unittests:: tsc:: projectReferences::", () => { commandLineArgs: ["--p", "app", "--pretty", "false"], }); + verifyTsc({ + scenario: "projectReferences", + subScenario: "referenced project with esnext module disallows synthetic default imports", + sys: () => + TestServerHost.createWatchedSystem({ + "/home/src/workspaces/project/lib/tsconfig.json": jsonToReadableText({ + compilerOptions: { + composite: true, + declaration: true, + module: "esnext", + moduleResolution: "bundler", + }, + }), + "/home/src/workspaces/project/lib/utils.ts": "export const test = () => 'test';", + "/home/src/workspaces/project/lib/utils.d.ts": "export declare const test: () => string;", + "/home/src/workspaces/project/app/tsconfig.json": jsonToReadableText({ + compilerOptions: { + module: "esnext", + moduleResolution: "bundler", + }, + references: [ + { path: "../lib" }, + ], + }), + "/home/src/workspaces/project/app/index.ts": `import Test from '../lib/utils';\nconsole.log(Test.test());`, + }), + commandLineArgs: ["--p", "app", "--pretty", "false"], + }); + verifyTsc({ scenario: "projectReferences", subScenario: "referencing ambient const enum from referenced project with preserveConstEnums", diff --git a/tests/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js b/tests/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js index bf990179392da..79610a168d1f0 100644 --- a/tests/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js +++ b/tests/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js @@ -86,6 +86,8 @@ declare const console: { log(msg: any): void; }; Output:: app/src/index.ts(2,28): error TS2613: Module '"/home/src/workspaces/project/app/src/local"' has no default export. Did you mean to use 'import { local } from "/home/src/workspaces/project/app/src/local"' instead? app/src/index.ts(3,28): error TS2613: Module '"/home/src/workspaces/project/node_modules/esm-package/index"' has no default export. Did you mean to use 'import { esm } from "/home/src/workspaces/project/node_modules/esm-package/index"' instead? +app/src/index.ts(4,28): error TS1192: Module '"/home/src/workspaces/project/lib/dist/a"' has no default export. +app/src/index.ts(5,28): error TS1192: Module '"/home/src/workspaces/project/lib/dist/a"' has no default export. //// [/home/src/workspaces/project/app/dist/local.js] diff --git a/tests/baselines/reference/tsc/projectReferences/referenced-project-with-esnext-module-disallows-synthetic-default-imports.js b/tests/baselines/reference/tsc/projectReferences/referenced-project-with-esnext-module-disallows-synthetic-default-imports.js new file mode 100644 index 0000000000000..f76acb14c6ead --- /dev/null +++ b/tests/baselines/reference/tsc/projectReferences/referenced-project-with-esnext-module-disallows-synthetic-default-imports.js @@ -0,0 +1,62 @@ +currentDirectory:: /home/src/workspaces/project useCaseSensitiveFileNames:: false +Input:: +//// [/home/src/workspaces/project/lib/tsconfig.json] +{ + "compilerOptions": { + "composite": true, + "declaration": true, + "module": "esnext", + "moduleResolution": "bundler" + } +} + +//// [/home/src/workspaces/project/lib/utils.ts] +export const test = () => 'test'; + +//// [/home/src/workspaces/project/lib/utils.d.ts] +export declare const test: () => string; + +//// [/home/src/workspaces/project/app/tsconfig.json] +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler" + }, + "references": [ + { + "path": "../lib" + } + ] +} + +//// [/home/src/workspaces/project/app/index.ts] +import Test from '../lib/utils'; +console.log(Test.test()); + +//// [/home/src/tslibs/TS/Lib/lib.d.ts] +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +declare const console: { log(msg: any): void; }; + + +/home/src/tslibs/TS/Lib/tsc.js --p app --pretty false +Output:: +app/index.ts(1,8): error TS1192: Module '"/home/src/workspaces/project/lib/utils"' has no default export. + + +//// [/home/src/workspaces/project/app/index.js] +import Test from '../lib/utils'; +console.log(Test.test()); + + + +exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated