NeuroAgent

How to Configure Module Imports in TypeScript 5.x

Solving 'Cannot find module' issues in TypeScript 5.x. Setting up moduleResolution, CommonJS/ES modules, and ts-node-dev. Complete guide for developers.

How to resolve module import issues when building a TypeScript project?

The project stopped running with the error: “Cannot find module ‘/home/andrew/CODE/JS/React/IdeaNick/backend/src/lib/ctx’ imported from /home/andrew/CODE/JS/React/IdeaNick/backend/src/index.ts”. The code editor finds the file and offers autocomplete, but the terminal cannot resolve the module path.

What I’ve discovered:

  • TypeScript was updated, which now complains about the Node parameter in ModuleResolution as deprecated
  • When switching to Bandler, there’s an incompatibility with the CommonJS module system
  • Different parameters are needed to run the backend and for type checking

Current configuration:

  • TypeScript: 5.7.3
  • ts-node-dev: 2.0.0
  • Run command: npm run devts-node-dev --watch ./.env --rs --exit-child ./src/index.ts

Error on startup:

Error: Cannot find module '/home/andrew/CODE/JS/React/IdeaNick/backend/src/lib/ctx' imported from /home/andrew/CODE/JS/React/IdeaNick/backend/src/index.ts'

How can I configure a consistent setup for both runtime and type checking?

NeuroAgent

TypeScript Cannot Find Module Due to Outdated Module Resolution Settings and Inconsistency Between CommonJS and ES Modules

To resolve this issue, you need to update your TypeScript configuration, set up the correct module resolution parameters, and ensure compatibility between development and execution tools.

Contents

Basic Reasons for Module Resolution Errors

The “Cannot find module” error occurs due to several common reasons:

  1. Outdated ModuleResolution parameters - TypeScript 5.x marks the “node” parameter as deprecated, causing conflicts
  2. Inconsistency between module systems - the project uses CommonJS, but tools try to work with ES modules
  3. Incorrect file paths - relative or absolute paths don’t match the compiler’s expectations
  4. Missing declaration files - some modules lack types (.d.ts files)

Important: Your code editor finds files because it uses its own path resolution mechanism, which differs from what TypeScript uses during compilation.

Setting Up ModuleResolution in TypeScript 5.x

In TypeScript 5.x, there have been changes to the module resolution system. The moduleResolution: "node" parameter is now considered deprecated and is replaced with moduleResolution: "bundler" for modern projects.

tsconfig.json Configuration

json
{
  "compilerOptions": {
    "module": "CommonJS",
    "moduleResolution": "NodeNext", // or "Node16"
    "target": "ES2020",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "outDir": "./dist",
    "rootDir": "./src"
  }
}

Options for moduleResolution:

  • NodeNext - for mixed CommonJS/ES projects
  • Node16 - for projects that follow Node.js 16+ module resolution
  • Bundler - for modern bundlers (Vite, esbuild, webpack)

Configuration for CommonJS and ES Modules

Compatibility Issue

Your situation is typical for projects that are migrating between CommonJS and ES modules. Here’s what you need to consider:

  1. If the project uses CommonJS:

    • Set module: "CommonJS"
    • Use moduleResolution: "NodeNext"
    • Add esModuleInterop: true
  2. If the project uses ES modules:

    • Set module: "ES2022" or higher
    • Use moduleResolution: "Bundler"
    • Add allowImportingTsExtensions: true

Example for Your Project

json
{
  "compilerOptions": {
    "module": "CommonJS",
    "moduleResolution": "NodeNext",
    "target": "ES2020",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "baseUrl": "./src",
    "paths": {
      "@lib/*": ["lib/*"],
      "@/*": ["./*"]
    }
  }
}

Setting Up ts-node-dev for Proper Operation

Problems with ts-node-dev often arise from inconsistency between TypeScript settings and startup parameters.

Updated Startup Command

Instead of the current command:

bash
ts-node-dev --watch ./.env --rs --exit-child ./src/index.ts

Use:

bash
ts-node-dev --watch ./.env --rs --exit-child --respawn --transpile-only ./src/index.ts

Alternative Startup Options

  1. Using tsx (modern alternative):
bash
npm install -D tsx
json
{
  "scripts": {
    "dev": "tsx --watch --env-file ./.env ./src/index.ts"
  }
}
  1. Using ts-node with correct flags:
bash
ts-node --esm --transpile-only ./src/index.ts

ts-node Configuration

Create a ts-node.config.js file:

javascript
module.exports = {
  compilerOptions: {
    module: "CommonJS",
    moduleResolution: "NodeNext",
    target: "ES2020",
    esModuleInterop: true,
    allowSyntheticDefaultImports: true,
    baseUrl: "./src",
    paths: {
      "@lib/*": ["lib/*"],
      "@/*": ["./*"]
    }
  }
};

Practical Solution for Your Project

To solve your specific problem with importing /home/andrew/CODE/JS/React/IdeaNick/backend/src/lib/ctx, follow these steps:

1. Update tsconfig.json

json
{
  "compilerOptions": {
    "module": "CommonJS",
    "moduleResolution": "NodeNext",
    "target": "ES2020",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "baseUrl": "./src",
    "paths": {
      "@lib/*": ["lib/*"],
      "@/*": ["./*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

2. Update package.json Scripts

json
{
  "scripts": {
    "dev": "ts-node-dev --watch ./.env --rs --exit-child --transpile-only ./src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js",
    "type-check": "tsc --noEmit"
  }
}

3. Check Imports

Make sure your imports match the project structure:

typescript
// Correct import options
import { someFunction } from './lib/ctx';
import { someFunction } from '@/lib/ctx';
import { someFunction } from '@lib/ctx';

// Avoid absolute paths outside configuration
// import { someFunction } from '/home/andrew/CODE/JS/React/IdeaNick/backend/src/lib/ctx';

4. Create Declaration Files (if needed)

If you have modules without types, create src/lib/ctx.d.ts:

typescript
declare module 'ctx' {
  export function someFunction(): void;
  export const someValue: string;
}

Checking and Testing Configuration

After making changes, perform the following checks:

1. Type Checking

bash
npm run type-check

2. Build Check

bash
npm run build

3. Startup Check

bash
npm run dev

4. Import Check in Editor

If the editor still can’t see modules, try:

  1. Restart VS Code
  2. Install TypeScript and ESLint extensions
  3. Check that the workspace uses the correct TypeScript version

5. Debugging Complex Cases

If the problem persists, add to tsconfig.json:

json
{
  "compilerOptions": {
    "traceResolution": true,
    "listEmittedFiles": true
  }
}

This will help you see which files TypeScript is trying to find and why.

Sources

  1. Official TypeScript Documentation - Module Resolution
  2. GitHub TypeScript - ModuleResolution changes
  3. ts-node documentation
  4. TypeScript 5.x Migration Guide
  5. CommonJS vs ES Modules

Conclusion

To solve the module import problem in your TypeScript project, you need to:

  1. Update TypeScript configuration - use moduleResolution: "NodeNext" instead of the deprecated “node”
  2. Configure consistency between CommonJS and ES modules - choose one system and stick to it
  3. Properly configure ts-node-dev - add the --transpile-only flag for faster development
  4. Use path aliases - configure baseUrl and paths for convenient imports
  5. Check file paths - ensure all relative paths are correct

The main problem in your case is the inconsistency between old TypeScript settings and the new compiler version. After applying the suggested configurations, your project should start correctly without module resolution errors.