This TypeScript error occurs when the compiler cannot resolve an imported module, either because it's not installed, has no type definitions, or the import path is incorrect. The fix typically involves installing the package, adding type definitions, or correcting the module path.
The "Cannot find module" error (TS2307) appears when TypeScript's module resolution system cannot locate the module you're trying to import. This can happen for several reasons: the package might not be installed in node_modules, the module may lack TypeScript type definitions, or the import path could be incorrect. TypeScript needs to understand both the runtime module location (where Node.js or your bundler will find it) and the type information for that module. When either piece is missing, you'll see this error even if the code would work in plain JavaScript. Common scenarios include: 1. **Missing packages**: The module is referenced in code but not installed via npm/yarn 2. **Missing type definitions**: The package exists but lacks TypeScript declarations (.d.ts files) 3. **Incorrect paths**: Relative imports with wrong file paths or missing file extensions 4. **Configuration issues**: tsconfig.json settings that prevent proper module resolution
First, check if the module exists in your node_modules folder:
# Check if package is in package.json
cat package.json | grep "module-name"
# List installed packages
npm list module-name
# If not installed, install it
npm install module-name
# For React example:
npm install react react-domAfter installing, try compiling again:
npx tsc
# or
npm run buildIf the error persists, the package may be installed but lacks type definitions.
Many JavaScript packages don't include TypeScript types by default. Install the corresponding @types package:
# General pattern
npm install --save-dev @types/package-name
# Common examples:
npm install --save-dev @types/node # For Node.js APIs
npm install --save-dev @types/react # For React
npm install --save-dev @types/lodash # For Lodash
npm install --save-dev @types/express # For ExpressAfter installation, TypeScript should recognize the module:
// This will now work
import express from "express";
import _ from "lodash";You can search for available types at [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) or [TypeSearch](https://www.typescriptlang.org/dt/search).
If you're importing your own files, verify the path is correct:
// WRONG - incorrect relative path
import { formatDate } from "./utilities/formatDate";
// Error: Cannot find module './utilities/formatDate'
// CORRECT - fix the path
import { formatDate } from "./utils/formatDate";
// WRONG - missing ../ to go up a directory
import { User } from "./types/User";
// When types is in parent directory
// CORRECT
import { User } from "../types/User";TypeScript file resolution rules:
- Don't include file extensions for .ts/.tsx files
- Use .js extension for .ts files when using ES modules with Node16/NodeNext
- Paths are case-sensitive on Linux/macOS
- Use ./ for same directory, ../ for parent directory
Ensure your tsconfig.json has the correct module resolution strategy:
{
"compilerOptions": {
"moduleResolution": "node",
"module": "commonjs",
"esModuleInterop": true,
"resolveJsonModule": true,
"typeRoots": ["./node_modules/@types"],
"baseUrl": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}For modern Node.js projects (v16+):
{
"compilerOptions": {
"moduleResolution": "node16",
"module": "node16"
}
}For bundlers (webpack, Vite, esbuild):
{
"compilerOptions": {
"moduleResolution": "bundler",
"module": "esnext"
}
}After changing tsconfig.json, restart your IDE/TypeScript server.
Module names are case-sensitive. Verify exact spelling:
// WRONG - incorrect casing
import React from "react"; // ✓ Correct
import React from "React"; // ✗ Won't work on Linux
// WRONG - typo in package name
import express from "expres"; // Missing 's'
import _ from "loadash"; // Should be "lodash"
// WRONG - incorrect file casing
import { User } from "./Types/user"; // File is ./types/User.tsUse your IDE's autocomplete to avoid typos. VS Code will suggest available modules as you type.
Sometimes node_modules gets corrupted or out of sync:
# Remove node_modules and lock file
rm -rf node_modules
rm package-lock.json # or yarn.lock / pnpm-lock.yaml
# Clear npm cache
npm cache clean --force
# Reinstall everything
npm install
# Restart TypeScript server in VS Code:
# Press Cmd/Ctrl + Shift + P, then "TypeScript: Restart TS Server"For monorepos or workspaces:
# If using npm workspaces
npm install --workspaces
# If using yarn workspaces
yarn install
# If using pnpm
pnpm install### Path Aliases and Runtime Resolution
TypeScript's paths option in tsconfig.json only affects compilation, not runtime. If you configure path aliases:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"@components/*": ["components/*"],
"@utils/*": ["utils/*"]
}
}
}You can import like this in TypeScript:
import { Button } from "@components/Button";However, Node.js won't understand these paths at runtime. You need additional tooling:
- For development with ts-node: npm install -D tsconfig-paths, then node -r tsconfig-paths/register dist/index.js
- For production: Use a bundler (webpack, esbuild, Vite) that resolves paths
- Alternative: Use [module-alias](https://www.npmjs.com/package/module-alias) package
### ES Modules vs CommonJS
Module resolution differs based on your module system:
CommonJS (Node.js default):
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node"
}
}
// Import syntax
import express from "express"; // Compiled to: const express = require("express")ES Modules (Modern Node.js with "type": "module" in package.json):
// package.json
{
"type": "module"
}
// tsconfig.json
{
"compilerOptions": {
"module": "node16",
"moduleResolution": "node16"
}
}With Node16/NodeNext, you must include .js extensions in relative imports:
// WRONG with Node16
import { formatDate } from "./utils/formatDate";
// CORRECT with Node16 (even though source file is .ts)
import { formatDate } from "./utils/formatDate.js";### Declaration Files for Custom Modules
If you have a JavaScript library without types, create a declaration file:
// types/my-untyped-lib.d.ts
declare module "my-untyped-lib" {
export function doSomething(param: string): number;
export interface Config {
enabled: boolean;
}
}Ensure this file is included in your tsconfig.json:
{
"include": ["src/**/*", "types/**/*"]
}### Bundler-Specific Considerations
Webpack: Use resolve.extensions to match TypeScript's module resolution:
module.exports = {
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
alias: {
'@components': path.resolve(__dirname, 'src/components/')
}
}
};Vite: Uses esbuild and supports tsconfig paths natively, but you may need vite-tsconfig-paths plugin for complex setups.
### Checking Module Resolution
Debug which file TypeScript is trying to load:
npx tsc --traceResolution | grep "module-name"This shows the full resolution chain and why it failed.
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript