microsoft / microsoft/TypeScript

`checkJs` skips `.mjs`/`.cjs` beside a `.d.mts`/`.d.cts`, but not `.js` beside a `.d.ts`

Offen
#64,312 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Vorherrschende Sprache
Go
Sterne
111k
Forks
14.3k
Ø Merge
2 T. 4 Std.
Gemergte PRs (30 T.)
132

Beschreibung

🔎 Search Terms

checkJs, allowJs, .d.mts, .d.cts, declaration file adjacent to implementation, file silently dropped from program, extension priority

🕗 Version & Regression Information

Reproduces identically on 5.9.3, 6.0.3, and 7.1.0-dev.20260916.1. Long-standing, not a regression.

⏯ Playground Link

Not applicable: needs two sibling files on disk plus moduleResolution: nodenext.

💻 Code

Three directories, identical but for extensions. Same tsconfig.json in each; package.json has "type": "module" only for the .mjs case.

index.js / index.mjs / index.cjs:

export const n = 1;

const bad = null;
bad.a.b.c();

index.d.ts / index.d.mts / index.d.cts:

export declare const n: number;
{
	"compilerOptions": {
		"target": "esnext",
		"module": "nodenext",
		"moduleResolution": "nodenext",
		"allowJs": true,
		"checkJs": true,
		"strict": true,
		"noEmit": true
	}
}
🙁 Actual behavior
index.js   + index.d.ts    ->  error TS18047: 'bad' is possibly 'null'.
index.mjs  + index.d.mts   ->  (no output)
index.cjs  + index.d.cts   ->  (no output)

The same authoring relationship — a hand-written declaration file beside its implementation — produces opposite outcomes based only on the file extension.

In the .mjs/.cjs cases the implementation is not merely unchecked, it is absent from the program: --listFiles reports only index.d.mts. In the .js case --listFiles reports both index.d.ts and index.js.

🙂 Expected behavior

The three rows should agree. Either all of them check the implementation, or none do.

I'd expect the .js row to be the correct one — the declaration file describes the module for consumers, and checkJs still checks the implementation — but consistency matters more than which way it goes.

Additional information

#47796 reported the .mjs/.mts variant and was closed as "Working as Intended", on the rationale that the JS file is a build artifact of the TS file, and that "the compiler only automatically pulls in one copy of a file with the same basename (the most TS-y one)".

That rationale doesn't extend to this case:

  • A .d.mts is not something a .mjs is emitted from, so the build-artifact framing doesn't apply. .d.ts + .js is the same relationship, and there the compiler does pull in both.
  • Neither does the one-copy-per-basename rule, for the same reason — index.js and index.d.ts are both in the program.

The failure is silent, which is what makes it expensive: a package shipping .mjs/.cjs with adjacent hand-written declarations gets no checking of its implementation at all, while every sibling module without a declaration file is checked normally. tsc exits 0 and CI is green. I found this only by deliberately breaking a file and noticing the build still passed. Per #47796, VS Code does report these errors, so the editor and CI silently disagree.

#64098 is the same silent-drop shape from wildcard include (hasFileWithHigherPriorityExtension), if the two are related.

So, concretely:

  1. Make the three rows consistent, or
  2. if this is intended, document which sibling extensions suppress checking, and emit a diagnostic when an input file is dropped from the program for this reason.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne damit, die Reproduktion in drei Verzeichnissen mit tsc --listFiles auszuführen, und vergleiche die Ergebnisse für .js/.d.ts, .mjs/.d.mts und .cjs/.d.cts. Verfolge das Verhalten der Erweiterungspriorität rund um hasFileWithHigherPriorityExtension, auf das in #64098 verwiesen wird. Als erledigt gilt die Aufgabe, wenn sich die drei Fälle konsistent verhalten und der Fall des stillen Verwerfens durch Tests abgedeckt ist.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
javascript, typescript
Bereich
compilers
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
52/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.