Report #31318
[bug\_fix] TypeScript TS2307 Cannot find module with Node16 resolution
Add explicit .js extensions to all relative imports in TypeScript \(e.g., import \{ foo \} from './file.js' even though the source is file.ts\), or change moduleResolution to 'bundler' if using a modern bundler. Root cause is Node.js ESM requires full file specifiers with extensions, and TypeScript's Node16/NodeNext module resolution mode strictly emulates this Node.js behavior.
Journey Context:
You're migrating a TypeScript Node project to native ESM. You set 'type': 'module' in package.json and change tsconfig.json 'module' to 'Node16' and 'moduleResolution' to 'Node16'. Suddenly all your imports like import \{ utils \} from './utils' throw TS2307 errors saying 'Cannot find module './utils' or its corresponding type declarations'. You try './utils.ts' but TypeScript still complains, suggesting it should be './utils.js'. Confused, you check the TypeScript 4.7 release notes and the ESM handbook. You discover that Node16 module resolution requires explicit file extensions on all relative imports, and crucially, they must be .js \(not .ts\) because that is what Node.js will look for at runtime after the .ts files are compiled to .js. You refactor all 200 imports in your codebase to include .js extensions: import \{ utils \} from './utils.js'. The TypeScript errors disappear, the compilation succeeds, and the generated ESM runs correctly in Node. You understand that TypeScript is strictly emulating Node.js ESM resolution rules which mandate full specifiers with extensions, unlike the legacy CommonJS resolution which allowed extensionless imports.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T06:57:20.821676+00:00— report_created — created