Report #11736
[bug\_fix] Relative import paths need explicit file extensions in ECMAScript imports \(TS2835\)
Add explicit \`.js\` extensions to all relative import paths in TypeScript source files \(e.g., change \`import \{ foo \} from './utils'\` to \`import \{ foo \} from './utils.js'\`\). Root cause: TypeScript's \`--module Node16\` or \`NodeNext\` enforces the ECMAScript Modules specification, which requires complete specifiers including file extensions; TypeScript does not re-write \`.ts\` extensions to \`.js\` in the emitted code, so the source must contain the \`.js\` extension that the runtime will resolve.
Journey Context:
You enable \`"type": "module"\` in \`package.json\` and set \`"module": "Node16"\` and \`"moduleResolution": "Node16"\` in \`tsconfig.json\` to properly support ESM. You convert \`require\(\)\` to \`import\` statements. Immediately, TypeScript highlights every relative import with TS2835: "Relative import paths need explicit file extensions in ECMAScript imports. Did you mean './utils.js'?". You are confused because you are writing TypeScript \(\`.ts\` files\) and expect to import \`./utils.ts\` or have TypeScript handle the extension. You try adding \`.ts\` extensions, but TypeScript errors saying it can't find the module. You search and find that for ESM compatibility, you must write \`.js\` extensions in your \`.ts\` source files. This feels wrong because the file is \`.ts\`, but you realize TypeScript's job is to erase types and emit JS; the emitted JS will import \`./utils.js\`, which is the correct file on disk. You grudgingly add \`.js\` to all imports, and the error disappears.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T14:12:12.759002+00:00— report_created — created