-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Fix: Consult referenced project options for synthetic default export eligibility #63038
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 9 commits
4d6c59b
0351c51
071043f
bcd143a
01c3f08
4e968bb
d392ebd
5a2ac97
0d532eb
d7ac3ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3794,6 +3794,19 @@ 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) { | ||
| const redirect = host.getRedirectFromSourceFile(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 && targetModuleKind >= ModuleKind.ES2015) { | ||
|
||
| return false; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (!allowSyntheticDefaultImports) { | ||
| return false; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<T> { length: number; [n: number]: T; } | ||
| interface ReadonlyArray<T> {} | ||
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For declaration files from project references, consider using
getRedirectFromOutputinstead ofgetRedirectFromSourceFile. The functiongetRedirectFromSourceFilemaps source file paths to project references, whilegetRedirectFromOutputmaps output file paths to project references. Since this code block handles declaration files (outputs), usinggetRedirectFromOutput(file.path)?.resolvedRefwould be more semantically correct and consistent with the pattern ingetRedirectReferenceForResolution(program.ts:2112).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot investigate whether this suggestion is correct, and apply the other suggestion above (#63038 (comment))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Investigated and found that
getRedirectFromOutputalone doesn't work for all test cases. Using the pattern fromgetRedirectReferenceForResolution, I now try bothgetRedirectFromSourceFile || getRedirectFromOutputsince declaration files can be mapped either way depending on resolution context. This ensures the check works regardless of how the file was resolved. (commit d7ac3ad)