Report #85946
[bug\_fix] Cannot find module './helper' or its corresponding type declarations. \(TS2307\) when using NodeNext or Node16 moduleResolution.
Add the explicit \`.js\` extension to the import specifier \(e.g., \`import \{ helper \} from './helper.js';\`\) even though the source file is \`./helper.ts\`. Ensure \`moduleResolution\` is set to \`NodeNext\` or \`Node16\`.
Journey Context:
Developer migrates their TypeScript project to ES modules by setting \`"type": "module"\` in \`package.json\` and updates \`tsconfig.json\` to use \`"module": "NodeNext"\` and \`"moduleResolution": "NodeNext"\` \(or Node16\) to align with Node.js native ESM resolution rules. They try to run the code and immediately hit "Cannot find module './utils'" errors on every relative import. They try changing the import to \`./utils.ts\`, but TypeScript forbids explicitly importing \`.ts\` extensions in ESM mode. They try \`./utils/index.js\`, which fails if the file is \`utils.ts\`. Confused, they consult the TypeScript documentation on ESM. They learn that under \`NodeNext\` resolution, TypeScript emulates Node.js's ESM loader, which requires complete specifiers including the file extension. Since the output file will be \`.js\`, the import must specify \`.js\`. Changing the import to \`./utils.js\` \(while the source remains \`utils.ts\`\) satisfies both the TypeScript compiler and the Node.js runtime.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T02:50:57.642326+00:00— report_created — created