Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -14465,6 +14465,20 @@ func (c *Checker) canHaveSyntheticDefault(file *ast.Node, moduleSymbol *ast.Symb
// 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 == core.ModuleKindNone && file.AsSourceFile().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
if c.program.GetRedirectForResolution(file.AsSourceFile()) != nil || c.program.GetProjectReferenceFromOutputDts(file.AsSourceFile().Path()) != nil {
// This is a declaration file from a project reference, so we can determine
Comment on lines +14471 to +14474
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GetProjectReferenceFromOutputDts(...) != nil check appears redundant here: Program.GetRedirectForResolution already consults both the source-to-output and output-dts-to-source project reference maps (and symlink mapping). Dropping the extra lookup would simplify the condition and avoid implying there are two independent mechanisms to check.

Copilot uses AI. Check for mistakes.
// its module format from the referenced project's options
targetModuleKind := c.program.GetEmitModuleFormatOfFile(file.AsSourceFile())
if usageMode == core.ModuleKindESNext && core.ModuleKindES2015 <= targetModuleKind && targetModuleKind <= core.ModuleKindESNext {
return false
}
}
}
}
if !c.allowSyntheticDefaultImports {
return false
Expand Down
35 changes: 35 additions & 0 deletions internal/execute/tsctests/tsc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3939,6 +3939,41 @@ func TestTscProjectReferences(t *testing.T) {
},
commandLineArgs: []string{"--p", "app", "--pretty", "false"},
},
{
subScenario: "referenced project with esnext module disallows synthetic default imports",
files: FileMap{
"/home/src/workspaces/project/lib/tsconfig.json": stringtestutil.Dedent(`
{
"compilerOptions": {
"composite": true,
"declaration": true,
"module": "esnext",
"moduleResolution": "bundler",
"rootDir": "src",
"outDir": "dist"
},
"include": ["src"]
}`),
"/home/src/workspaces/project/lib/src/utils.ts": "export const test = () => 'test';",
"/home/src/workspaces/project/lib/dist/utils.d.ts": "export declare const test: () => string;",
"/home/src/workspaces/project/app/tsconfig.json": stringtestutil.Dedent(`
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler"
},
"references": [
{ "path": "../lib" }
]
}`),
"/home/src/workspaces/project/app/index.ts": stringtestutil.Dedent(`
import TestSrc from '../lib/src/utils'; // Error
import TestDecl from '../lib/dist/utils'; // Error
console.log(TestSrc.test());
console.log(TestDecl.test());`),
},
commandLineArgs: []string{"--p", "app", "--pretty", "false"},
},
{
subScenario: "referencing ambient const enum from referenced project with preserveConstEnums",
files: FileMap{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,17 @@ Output::
2 export = x;
  ~~~~~~~~~~~

sub-project/index.js:1:8 - error TS1192: Module '"/home/src/workspaces/solution/common/index"' has no default export.

Found 2 errors in the same file, starting at: common/index.ts:1
1 import mod from '../common';
   ~~~


Found 3 errors in 2 files.

Errors Files
2 common/index.ts:1
1 sub-project/index.js:1

//// [/home/src/tslibs/TS/Lib/lib.es2025.full.d.ts] *Lib*
/// <reference no-default-lib="true"/>
Expand All @@ -119,9 +128,7 @@ interface Symbol {
declare const console: { log(msg: any): void; };
//// [/home/src/workspaces/out/sub-project-2/index.d.ts] *new*
export declare function getVar(): {
key: {
val: number;
};
key: any;
};

//// [/home/src/workspaces/out/sub-project-2/index.js] *new*
Expand All @@ -134,7 +141,7 @@ export function getVar() {
}

//// [/home/src/workspaces/out/sub-project-2/tsconfig.tsbuildinfo] *new*
{"version":"FakeTSVersion","root":[3],"fileNames":["lib.es2025.full.d.ts","../sub-project/index.d.ts","../../solution/sub-project-2/index.js"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},"b13b16e08eb0717669fa55818828b2cb-export declare const m: {\n val: number;\n};\n",{"version":"56ecb5738c72a131a1514873df723721-import { m } from '../sub-project/index';\n\nconst variable = {\n key: m,\n};\n\nexport function getVar() {\n return variable;\n}","signature":"f6a0b1edad82fddabb5c98ad5da1660d-export declare function getVar(): {\n key: {\n val: number;\n };\n};\n","impliedNodeFormat":1}],"fileIdsList":[[2]],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"esModuleInterop":true,"outDir":"..","rootDir":"../../solution","skipLibCheck":true},"referencedMap":[[3,1]],"latestChangedDtsFile":"./index.d.ts"}
{"version":"FakeTSVersion","root":[3],"fileNames":["lib.es2025.full.d.ts","../sub-project/index.d.ts","../../solution/sub-project-2/index.js"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},"ce0233db1f3aabecabdb072a4f4c8d1e-export declare const m: any;\n",{"version":"56ecb5738c72a131a1514873df723721-import { m } from '../sub-project/index';\n\nconst variable = {\n key: m,\n};\n\nexport function getVar() {\n return variable;\n}","signature":"cb28999e3dc9364c7b77f755d2449d70-export declare function getVar(): {\n key: any;\n};\n","impliedNodeFormat":1}],"fileIdsList":[[2]],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"esModuleInterop":true,"outDir":"..","rootDir":"../../solution","skipLibCheck":true},"referencedMap":[[3,1]],"latestChangedDtsFile":"./index.d.ts"}
//// [/home/src/workspaces/out/sub-project-2/tsconfig.tsbuildinfo.readable.baseline.txt] *new*
{
"version": "FakeTSVersion",
Expand Down Expand Up @@ -166,18 +173,18 @@ export function getVar() {
},
{
"fileName": "../sub-project/index.d.ts",
"version": "b13b16e08eb0717669fa55818828b2cb-export declare const m: {\n val: number;\n};\n",
"signature": "b13b16e08eb0717669fa55818828b2cb-export declare const m: {\n val: number;\n};\n",
"version": "ce0233db1f3aabecabdb072a4f4c8d1e-export declare const m: any;\n",
"signature": "ce0233db1f3aabecabdb072a4f4c8d1e-export declare const m: any;\n",
"impliedNodeFormat": "CommonJS"
},
{
"fileName": "../../solution/sub-project-2/index.js",
"version": "56ecb5738c72a131a1514873df723721-import { m } from '../sub-project/index';\n\nconst variable = {\n key: m,\n};\n\nexport function getVar() {\n return variable;\n}",
"signature": "f6a0b1edad82fddabb5c98ad5da1660d-export declare function getVar(): {\n key: {\n val: number;\n };\n};\n",
"signature": "cb28999e3dc9364c7b77f755d2449d70-export declare function getVar(): {\n key: any;\n};\n",
"impliedNodeFormat": "CommonJS",
"original": {
"version": "56ecb5738c72a131a1514873df723721-import { m } from '../sub-project/index';\n\nconst variable = {\n key: m,\n};\n\nexport function getVar() {\n return variable;\n}",
"signature": "f6a0b1edad82fddabb5c98ad5da1660d-export declare function getVar(): {\n key: {\n val: number;\n };\n};\n",
"signature": "cb28999e3dc9364c7b77f755d2449d70-export declare function getVar(): {\n key: any;\n};\n",
"impliedNodeFormat": 1
}
}
Expand All @@ -203,19 +210,17 @@ export function getVar() {
]
},
"latestChangedDtsFile": "./index.d.ts",
"size": 1592
"size": 1546
}
//// [/home/src/workspaces/out/sub-project/index.d.ts] *new*
export declare const m: {
val: number;
};
export declare const m: any;

//// [/home/src/workspaces/out/sub-project/index.js] *new*
import mod from '../common';
export const m = mod;

//// [/home/src/workspaces/out/sub-project/tsconfig.tsbuildinfo] *new*
{"version":"FakeTSVersion","root":[4],"fileNames":["lib.es2025.full.d.ts","../../solution/common/obj.json","../../solution/common/index.d.ts","../../solution/sub-project/index.js"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"d47747c9a3b20f363d6de91e2bd8ed62-{\n \"val\": 42,\n}"},"641f5162aeaa035322008b19df89c663-import x = require(\"./obj.json\");\nexport = x;\n",{"version":"4c69d0c670e9dc788b5e107f277aa8ab-import mod from '../common';\n\nexport const m = mod;","signature":"b13b16e08eb0717669fa55818828b2cb-export declare const m: {\n val: number;\n};\n","impliedNodeFormat":1}],"fileIdsList":[[2],[3]],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"esModuleInterop":true,"outDir":"..","rootDir":"../../solution","skipLibCheck":true},"referencedMap":[[3,1],[4,2]],"latestChangedDtsFile":"./index.d.ts"}
{"version":"FakeTSVersion","root":[4],"fileNames":["lib.es2025.full.d.ts","../../solution/common/obj.json","../../solution/common/index.d.ts","../../solution/sub-project/index.js"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"d47747c9a3b20f363d6de91e2bd8ed62-{\n \"val\": 42,\n}"},"641f5162aeaa035322008b19df89c663-import x = require(\"./obj.json\");\nexport = x;\n",{"version":"4c69d0c670e9dc788b5e107f277aa8ab-import mod from '../common';\n\nexport const m = mod;","signature":"ce0233db1f3aabecabdb072a4f4c8d1e-export declare const m: any;\n","impliedNodeFormat":1}],"fileIdsList":[[2],[3]],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"esModuleInterop":true,"outDir":"..","rootDir":"../../solution","skipLibCheck":true},"referencedMap":[[3,1],[4,2]],"semanticDiagnosticsPerFile":[[4,[{"pos":7,"end":10,"code":1192,"category":1,"messageKey":"Module_0_has_no_default_export_1192","messageArgs":["\"/home/src/workspaces/solution/common/index\""]}]]],"latestChangedDtsFile":"./index.d.ts"}
//// [/home/src/workspaces/out/sub-project/tsconfig.tsbuildinfo.readable.baseline.txt] *new*
{
"version": "FakeTSVersion",
Expand Down Expand Up @@ -264,11 +269,11 @@ export const m = mod;
{
"fileName": "../../solution/sub-project/index.js",
"version": "4c69d0c670e9dc788b5e107f277aa8ab-import mod from '../common';\n\nexport const m = mod;",
"signature": "b13b16e08eb0717669fa55818828b2cb-export declare const m: {\n val: number;\n};\n",
"signature": "ce0233db1f3aabecabdb072a4f4c8d1e-export declare const m: any;\n",
"impliedNodeFormat": "CommonJS",
"original": {
"version": "4c69d0c670e9dc788b5e107f277aa8ab-import mod from '../common';\n\nexport const m = mod;",
"signature": "b13b16e08eb0717669fa55818828b2cb-export declare const m: {\n val: number;\n};\n",
"signature": "ce0233db1f3aabecabdb072a4f4c8d1e-export declare const m: any;\n",
"impliedNodeFormat": 1
}
}
Expand Down Expand Up @@ -299,8 +304,25 @@ export const m = mod;
"../../solution/common/index.d.ts"
]
},
"semanticDiagnosticsPerFile": [
[
"../../solution/sub-project/index.js",
[
{
"pos": 7,
"end": 10,
"code": 1192,
"category": 1,
"messageKey": "Module_0_has_no_default_export_1192",
"messageArgs": [
"\"/home/src/workspaces/solution/common/index\""
]
}
]
]
],
"latestChangedDtsFile": "./index.d.ts",
"size": 1595
"size": 1773
}
//// [/home/src/workspaces/solution/common/index.d.ts] *new*
import x = require("./obj.json");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ ExitStatus:: DiagnosticsPresent_OutputsGenerated
Output::
app/src/index.ts(1,8): 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(2,8): 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(3,8): error TS1192: Module '"/home/src/workspaces/project/lib/dist/a"' has no default export.
app/src/index.ts(4,8): error TS1192: Module '"/home/src/workspaces/project/lib/dist/a"' has no default export.
//// [/home/src/tslibs/TS/Lib/lib.es2025.full.d.ts] *Lib*
/// <reference no-default-lib="true"/>
interface Boolean {}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
currentDirectory::/home/src/workspaces/project
useCaseSensitiveFileNames::true
Input::
//// [/home/src/workspaces/project/app/index.ts] *new*
import TestSrc from '../lib/src/utils'; // Error
import TestDecl from '../lib/dist/utils'; // Error
console.log(TestSrc.test());
console.log(TestDecl.test());
//// [/home/src/workspaces/project/app/tsconfig.json] *new*
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler"
},
"references": [
{ "path": "../lib" }
]
}
//// [/home/src/workspaces/project/lib/dist/utils.d.ts] *new*
export declare const test: () => string;
//// [/home/src/workspaces/project/lib/src/utils.ts] *new*
export const test = () => 'test';
//// [/home/src/workspaces/project/lib/tsconfig.json] *new*
{
"compilerOptions": {
"composite": true,
"declaration": true,
"module": "esnext",
"moduleResolution": "bundler",
"rootDir": "src",
"outDir": "dist"
},
"include": ["src"]
}

tsgo --p app --pretty false
ExitStatus:: DiagnosticsPresent_OutputsGenerated
Output::
app/index.ts(1,8): error TS1192: Module '"/home/src/workspaces/project/lib/dist/utils"' has no default export.
app/index.ts(2,8): error TS1192: Module '"/home/src/workspaces/project/lib/dist/utils"' has no default export.
//// [/home/src/tslibs/TS/Lib/lib.es2025.full.d.ts] *Lib*
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }
interface ReadonlyArray<T> {}
interface SymbolConstructor {
(desc?: string | number): symbol;
for(name: string): symbol;
readonly toStringTag: symbol;
}
declare var Symbol: SymbolConstructor;
interface Symbol {
readonly [Symbol.toStringTag]: string;
}
declare const console: { log(msg: any): void; };
//// [/home/src/workspaces/project/app/index.js] *new*
import TestSrc from '../lib/src/utils'; // Error
import TestDecl from '../lib/dist/utils'; // Error
console.log(TestSrc.test());
console.log(TestDecl.test());


Loading