From 06daa796270c2bea317bcbcafa28927abee662d0 Mon Sep 17 00:00:00 2001 From: Hardik Kaurani Date: Mon, 19 Oct 2026 12:34:51 +0530 Subject: [PATCH] Fix checkJs behavior for .mjs and .cjs files next to declarations (#64312) Drop legacy .js/.d.ts wildcard exception from extension priority to align behavior across .js, .mjs, and .cjs. Fixes #64312 --- tsc/internal/tsoptions/tsconfigparsing.go | 6 --- .../compiler/checkJsExtensionPriority.symbols | 15 ++++++ .../compiler/checkJsExtensionPriority.types | 15 ++++++ ...ckJsExtensionPriority_includeOrder.symbols | 14 ++++++ ...heckJsExtensionPriority_includeOrder.types | 14 ++++++ .../compiler/checkJsExtensionPriority.ts | 42 +++++++++++++++++ .../checkJsExtensionPriority_includeOrder.ts | 46 +++++++++++++++++++ 7 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority.types create mode 100644 tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority_includeOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority_includeOrder.types create mode 100644 tsc/testdata/tests/cases/compiler/checkJsExtensionPriority.ts create mode 100644 tsc/testdata/tests/cases/compiler/checkJsExtensionPriority_includeOrder.ts diff --git a/tsc/internal/tsoptions/tsconfigparsing.go b/tsc/internal/tsoptions/tsconfigparsing.go index 16b231c42e126..cd2254f498e55 100644 --- a/tsc/internal/tsoptions/tsconfigparsing.go +++ b/tsc/internal/tsoptions/tsconfigparsing.go @@ -1807,12 +1807,6 @@ func hasFileWithHigherPriorityExtension(file tspath.RootedFilePath, extensions [ return false } if hasFile(file.ChangeExtension(ext)) { - if ext == tspath.ExtensionDts && (file.ExtensionIs(tspath.ExtensionJs) || file.ExtensionIs(tspath.ExtensionJsx)) { - // LEGACY BEHAVIOR: An off-by-one bug somewhere in the extension priority system for wildcard module loading allowed declaration - // files to be loaded alongside their js(x) counterparts. We regard this as generally undesirable, but retain the behavior to - // prevent breakage. - continue - } return true } } diff --git a/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority.symbols b/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority.symbols new file mode 100644 index 0000000000000..7b93d669d151a --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority.symbols @@ -0,0 +1,15 @@ +//// [tests/cases/compiler/checkJsExtensionPriority.ts] //// + +=== /a.d.ts === +export declare const n: number; +>n : Symbol(n, Decl(a.d.ts, 0, 20)) + +=== /b.d.mts === +export declare const n: number; +>n : Symbol(n, Decl(b.d.mts, 0, 20)) + +=== /c.d.cts === +export declare const n: number; +>n : Symbol(n, Decl(c.d.cts, 0, 20)) + + diff --git a/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority.types b/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority.types new file mode 100644 index 0000000000000..e2d4db7f44368 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority.types @@ -0,0 +1,15 @@ +//// [tests/cases/compiler/checkJsExtensionPriority.ts] //// + +=== /a.d.ts === +export declare const n: number; +>n : number + +=== /b.d.mts === +export declare const n: number; +>n : number + +=== /c.d.cts === +export declare const n: number; +>n : number + + diff --git a/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority_includeOrder.symbols b/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority_includeOrder.symbols new file mode 100644 index 0000000000000..a18c297699957 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority_includeOrder.symbols @@ -0,0 +1,14 @@ +//// [tests/cases/compiler/checkJsExtensionPriority_includeOrder.ts] //// + +=== /a.d.ts === +export declare const n: number; +>n : Symbol(n, Decl(a.d.ts, 0, 20)) + +=== /b.d.mts === +export declare const n: number; +>n : Symbol(n, Decl(b.d.mts, 0, 20)) + +=== /c.d.cts === +export declare const n: number; +>n : Symbol(n, Decl(c.d.cts, 0, 20)) + diff --git a/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority_includeOrder.types b/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority_includeOrder.types new file mode 100644 index 0000000000000..9e63783c747bb --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/checkJsExtensionPriority_includeOrder.types @@ -0,0 +1,14 @@ +//// [tests/cases/compiler/checkJsExtensionPriority_includeOrder.ts] //// + +=== /a.d.ts === +export declare const n: number; +>n : number + +=== /b.d.mts === +export declare const n: number; +>n : number + +=== /c.d.cts === +export declare const n: number; +>n : number + diff --git a/tsc/testdata/tests/cases/compiler/checkJsExtensionPriority.ts b/tsc/testdata/tests/cases/compiler/checkJsExtensionPriority.ts new file mode 100644 index 0000000000000..b93888dac4e54 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/checkJsExtensionPriority.ts @@ -0,0 +1,42 @@ +// @Filename: /tsconfig.json +{ + "compilerOptions": { + "target": "esnext", + "module": "nodenext", + "moduleResolution": "nodenext", + "allowJs": true, + "checkJs": true, + "strict": true, + "noEmit": true + } +} + +// @Filename: /package.json +{ + "type": "module" +} + +// @Filename: /a.js +export const n = 1; +const bad = null; +bad.a.b.c(); + +// @Filename: /a.d.ts +export declare const n: number; + +// @Filename: /b.mjs +export const n = 1; +const bad = null; +bad.a.b.c(); + +// @Filename: /b.d.mts +export declare const n: number; + +// @Filename: /c.cjs +export const n = 1; +const bad = null; +bad.a.b.c(); + +// @Filename: /c.d.cts +export declare const n: number; + diff --git a/tsc/testdata/tests/cases/compiler/checkJsExtensionPriority_includeOrder.ts b/tsc/testdata/tests/cases/compiler/checkJsExtensionPriority_includeOrder.ts new file mode 100644 index 0000000000000..88151cbbbebc9 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/checkJsExtensionPriority_includeOrder.ts @@ -0,0 +1,46 @@ +// @Filename: /tsconfig.json +{ + "compilerOptions": { + "target": "esnext", + "module": "nodenext", + "moduleResolution": "nodenext", + "allowJs": true, + "checkJs": true, + "strict": true, + "noEmit": true + }, + "include": [ + "**/*.js", + "**/*.d.ts", + "**/*.mjs", + "**/*.d.mts", + "**/*.cjs", + "**/*.d.cts" + ] +} + +// @Filename: /package.json +{ + "type": "module" +} + +// @Filename: /a.js +const bad = null; +bad.a(); + +// @Filename: /a.d.ts +export declare const n: number; + +// @Filename: /b.mjs +const bad = null; +bad.b(); + +// @Filename: /b.d.mts +export declare const n: number; + +// @Filename: /c.cjs +const bad = null; +bad.c(); + +// @Filename: /c.d.cts +export declare const n: number;