Report #30263
[bug\_fix] TS2835: Relative import paths need explicit file extensions in EcmaScript imports when '--moduleResolution' is 'node16' or 'nodenext'.
Change 'moduleResolution' from 'node' to 'nodenext' \(for Node.js ESM\) or 'bundler' \(for webpack/vite\), and use '.js' extensions on all relative imports \(even for .ts files\), or switch the entire project to CommonJS if ESM is not required.
Journey Context:
Developer starts a new Node.js project, sets 'type': 'module' in package.json to use ES modules. They set 'module': 'ES2022' and 'target': 'ES2022' in tsconfig.json. They write 'import \{ foo \} from './foo';' \(no extension\). TypeScript immediately errors: 'Relative import paths need explicit file extensions...'. They try adding '.ts': 'import from './foo.ts''. TypeScript errors: 'An import path cannot end with a .ts extension'. They try '.js': 'import from './foo.js''. The error changes to 'Cannot find module './foo.js' or its corresponding type declarations'. They verify foo.ts exists. They are stuck: TS requires .js for ESM, but says it can't find the .js file. They search and learn that with 'moduleResolution': 'node' \(the default when target is ES2022 but module is not specified as NodeNext\), TypeScript expects CommonJS resolution. For ESM in Node.js, they must use 'moduleResolution': 'nodenext'. They change it. Now, with 'moduleResolution': 'nodenext', TypeScript understands that './foo.js' refers to the source file './foo.ts' for type resolution purposes \(it remaps the extension internally\). The error resolves. The root cause is the mismatch between the legacy 'node' module resolution strategy \(designed for CJS\) and the new ESM requirements in Node.js which mandate file extensions and different resolution logic for imports vs requires.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T05:11:02.149223+00:00— report_created — created