Fix: TS2307 Cannot find module or its corresponding type declarations

The Error

You open your TypeScript project and the compiler throws one of these:

Missing a type definition package:

error TS2307: Cannot find module 'express' or its corresponding type declarations.

Missing a global name like process or __dirname:

error TS2304: Cannot find name 'process'.
error TS2304: Cannot find name '__dirname'.
error TS2304: Cannot find name 'require'.

Importing a JavaScript package that ships no types:

error TS7016: Could not find a declaration file for module 'some-js-library'.
'/home/user/my-app/node_modules/some-js-library/index.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/some-js-library` if it exists or add a new declaration (.d.ts)
  file containing `declare module 'some-js-library';`

The npm install variant:

Could not find a declaration file for module 'some-js-library'.

All of these mean the same fundamental thing: TypeScript can see the JavaScript code (or knows a module exists), but it can’t find type information for it. Without types, TypeScript doesn’t know what shape the module’s exports have, so it refuses to compile (or flags it as any).

Why This Happens

TypeScript needs type definitions for every module you import. Those definitions can come from three places:

  1. Bundled types. The package itself ships a .d.ts file (look for a types or typings field in its package.json). Most modern packages do this.
  2. DefinitelyTyped. Community-maintained type definitions published as @types/package-name on npm. This covers popular packages that don’t ship their own types.
  3. Your own declaration files. A .d.ts file in your project where you manually declare the module’s shape.

When none of these exist for a module you import, TypeScript throws one of the errors above.

The most common causes:

  • You installed a package but not its @types/ counterpart. The package itself has no bundled types and you haven’t installed the DefinitelyTyped package.
  • Your tsconfig.json is misconfigured. The include, exclude, typeRoots, or types settings are filtering out type definitions that exist on disk.
  • You’re using Node.js globals (process, __dirname, Buffer) without @types/node. These aren’t part of TypeScript’s default library — they come from @types/node.
  • Your moduleResolution setting doesn’t match your project setup. TypeScript can’t find modules that Node.js or your bundler would resolve fine.
  • The package is a pure JavaScript library with no types anywhere. No bundled types, no @types/ package, nothing. You need to declare it yourself.

Fix 1: Install the @types/ Package

Most popular npm packages have type definitions on DefinitelyTyped. Install the matching @types/ package as a dev dependency:

npm install --save-dev @types/node

For multiple packages:

npm install --save-dev @types/node @types/react @types/express

Common @types/ packages

PackageTypes PackageWhat it covers
Node.js built-ins@types/nodeprocess, Buffer, __dirname, require, fs, path, etc.
React@types/reactuseState, useEffect, JSX types, component types
React DOM@types/react-domcreateRoot, render, hydrate
Express@types/expressRequest, Response, NextFunction, router types
Jest@types/jestdescribe, it, expect, mock types
Mocha@types/mochadescribe, it, before, after
Lodash@types/lodashAll lodash utility function types
jQuery@types/jquery$, DOM manipulation types
Cors@types/corsCORS middleware types
Cookie Parser@types/cookie-parserCookie parser middleware types
Supertest@types/supertestHTTP assertion library types
UUID@types/uuidUUID generation function types

How to check if @types/ exists for a package: Search on npm:

npm search @types/package-name

Or visit https://www.npmjs.com/~types and search there.

Note: Some packages bundle their own types and don’t need a separate @types/ install. If a package’s package.json has a types or typings field, it ships its own types. Examples include axios, zod, prisma, and date-fns.

Fix 2: Create a Declaration File

If no @types/ package exists and the library doesn’t ship types, create your own declaration file.

Quick fix: declare the module as any

Create a file called declarations.d.ts (or any .d.ts name) in your project’s source directory:

declare module 'some-js-library';

This tells TypeScript “this module exists, treat all its exports as any.” You lose type checking for that module, but the error goes away.

Better: declare the exports you use

If you know the module’s API, declare specific types:

declare module 'some-js-library' {
  export function doSomething(input: string): number;
  export function formatOutput(data: unknown): string;
  export default class Client {
    constructor(apiKey: string);
    fetch(url: string): Promise<unknown>;
  }
}

Declaring CSS/image/asset modules

Bundlers like Webpack and Vite let you import non-JavaScript files. TypeScript doesn’t understand these by default:

error TS2307: Cannot find module './styles.css' or its corresponding type declarations.
error TS2307: Cannot find module './logo.png' or its corresponding type declarations.

Create a declaration file for these asset types:

// assets.d.ts

// For CSS Modules (.module.css) — class names as string keys
declare module '*.css' {
  const classes: Record<string, string>;
  export default classes;
}

declare module '*.svg' {
  const content: string;
  export default content;
}

declare module '*.png' {
  const src: string;
  export default src;
}

declare module '*.jpg' {
  const src: string;
  export default src;
}

Note: If you’re using Vite, it ships vite/client types that already handle these. Add "types": ["vite/client"] to your tsconfig.json or add /// <reference types="vite/client" /> at the top of a .d.ts file. If you’re also seeing Vite-specific import resolution errors, see Fix: Failed to resolve import in Vite.

Where to put .d.ts files

Place declaration files anywhere TypeScript can see them. The most common locations:

  • src/types/ or src/@types/ — a dedicated types directory inside your source root.
  • Project root — alongside tsconfig.json.
  • Any directory listed in include in your tsconfig.json.

The file must be within a path matched by the include pattern in tsconfig.json. If your include is set to ["src/**/*"] and you put the .d.ts file in the project root, TypeScript won’t see it.

Fix 3: Fix tsconfig.json

A misconfigured tsconfig.json is a common cause of type resolution failures, even when the types exist on disk.

include and exclude

The include array tells TypeScript which files to compile. If your declaration files or source files aren’t covered by the pattern, TypeScript ignores them:

{
  "compilerOptions": { ... },
  "include": ["src/**/*"]
}

With this config, a .d.ts file in the project root won’t be picked up. Either move it into src/ or expand include:

{
  "include": ["src/**/*", "declarations.d.ts"]
}

If you’re using exclude to ignore directories, make sure you’re not accidentally excluding your type files:

{
  "exclude": ["node_modules", "dist", "build"]
}

typeRoots and types

By default, TypeScript automatically loads type definitions from every @types/ package in node_modules. If you set typeRoots or types, you override this behavior.

typeRoots specifies which directories TypeScript looks in for type packages:

{
  "compilerOptions": {
    "typeRoots": ["./node_modules/@types", "./src/types"]
  }
}

If you set typeRoots to only your custom directory, TypeScript stops loading @types/ packages from node_modules. Always include "./node_modules/@types" if you set this.

types specifies which @types/ packages to include. When set, only the listed packages are loaded:

{
  "compilerOptions": {
    "types": ["node", "jest"]
  }
}

With this config, only @types/node and @types/jest are loaded. If you have @types/express installed, TypeScript won’t use it. This is a common gotcha — if your project works fine but a specific type package is ignored, check if types is set.

If you’re unsure, remove both typeRoots and types to restore the default behavior (load all @types/ packages automatically).

moduleResolution

This setting controls how TypeScript finds modules. The wrong value causes TypeScript to fail at finding modules that your runtime resolves fine.

{
  "compilerOptions": {
    "moduleResolution": "node"
  }
}
ValueWhen to use
"node"Legacy Node.js CommonJS projects
"node16" / "nodenext"Node.js projects using ESM ("type": "module" in package.json)
"bundler"Projects using Webpack, Vite, esbuild, or other bundlers

If you’re using a modern framework (Next.js, Vite, Remix), use "bundler". If you’re getting Module not found: Can’t resolve errors from your bundler alongside TypeScript errors, the moduleResolution mismatch is often the cause. If you’re writing a Node.js library targeting ESM, use "nodenext". The old "node" value doesn’t understand package.json exports fields, conditional exports, or ESM subpath patterns — so it fails to resolve modules that newer resolution modes handle fine.

lib

The lib option controls which built-in type definitions TypeScript includes. If you’re getting TS2304: Cannot find name 'Map' or Cannot find name 'Promise', your lib is too restrictive:

{
  "compilerOptions": {
    "lib": ["ES2022", "DOM", "DOM.Iterable"]
  }
}
  • ES2022 (or whichever target you need) — includes Promise, Map, Set, Array.prototype.at(), etc.
  • DOM — includes document, window, HTMLElement, fetch, etc. Omit this for Node.js-only projects.
  • DOM.Iterable — includes iterable DOM types like NodeList iteration.

For Node.js projects without a browser, don’t include DOM. If you need fetch types in Node.js 18+, @types/node (version 18+) includes them.

Fix 4: Add Global Type Declarations

Some errors are about global variables that exist at runtime but TypeScript doesn’t know about.

process, __dirname, __filename, require — install @types/node

These are Node.js globals. Install @types/node:

npm install --save-dev @types/node

__dirname and __filename in ESM

In ESM modules ("type": "module"), __dirname and __filename don’t exist. This is a Node.js limitation, not a TypeScript one. Use import.meta instead:

import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

If you’re on Node.js 21.2+, you can use import.meta.dirname and import.meta.filename directly.

Custom properties on window

If you add custom properties to window and get TS2339: Property 'myApp' does not exist on type 'Window & typeof globalThis':

// global.d.ts
declare global {
  interface Window {
    myApp: {
      version: string;
      config: Record<string, unknown>;
    };
  }
}

export {};

The export {} at the bottom is important. It makes the file a module, which is necessary for declare global to merge declarations into the global scope correctly. Without it, TypeScript treats the file as a script — declarations in script files are already global, but mixing script-style and module-style declarations across your project leads to unpredictable behavior. Always include export {} in .d.ts files that use declare global.

Custom environment variables (process.env)

To type your environment variables:

// env.d.ts
declare global {
  namespace NodeJS {
    interface ProcessEnv {
      NODE_ENV: 'development' | 'production' | 'test';
      DATABASE_URL: string;
      API_KEY: string;
    }
  }
}

export {};

This gives you autocomplete and type checking on process.env.DATABASE_URL.

Edge Cases

JSX type errors after React 19 / TypeScript 5.x

If you’re getting errors like Cannot find name 'React' or TS2786: 'Component' cannot be used as a JSX component after upgrading, check two things:

  1. Your @types/react version must match your React version. React 18 needs @types/react@18.x. React 19 bundles its own types — remove @types/react entirely.

  2. Set jsx correctly in tsconfig.json:

    {
      "compilerOptions": {
        "jsx": "react-jsx"
      }
    }

    Using "react-jsx" (or "react-jsxdev") means you don’t need import React from 'react' at the top of every file. The older "react" value requires the import.

Monorepo type sharing

In a monorepo, packages often need to import types from sibling packages. Common issues:

TypeScript can’t find sibling package types:

Add project references in tsconfig.json:

{
  "references": [
    { "path": "../shared" },
    { "path": "../types" }
  ]
}

The referenced project needs "composite": true and "declaration": true in its own tsconfig.json:

{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "outDir": "./dist"
  }
}

Types fall out of sync across packages:

Use tsc --build (or tsc -b) to build in dependency order. This ensures declaration files are generated before dependent packages try to use them.

.d.ts file not being picked up

If you created a declaration file and TypeScript still complains:

  1. Check include in tsconfig.json. The .d.ts file must be in a matched path.
  2. Check exclude. Make sure it’s not excluded.
  3. The file must have the .d.ts extension, not .ts. A regular .ts file with declare module works differently from a .d.ts file — it’s treated as a module, not an ambient declaration.
  4. Restart the TypeScript server in your editor. VS Code caches type information aggressively.

skipLibCheck

If you’re getting type errors inside node_modules or in .d.ts files you didn’t write, you can skip type checking for all declaration files:

{
  "compilerOptions": {
    "skipLibCheck": true
  }
}

This tells TypeScript to not type-check .d.ts files. It speeds up compilation and avoids errors caused by conflicting type definitions between packages. Most projects should have this enabled. It’s a recommended default in many framework starter templates (Next.js, Vite, Create React App).

Warning: skipLibCheck can hide real type errors in your own .d.ts files. If you’re authoring a library with complex declaration files, disable it during development to catch issues early.

Still Not Working?

VS Code not picking up types

VS Code runs its own TypeScript server. If you install types and VS Code still shows errors:

  1. Open the command palette (Ctrl+Shift+P / Cmd+Shift+P).
  2. Run “TypeScript: Restart TS Server”.

This forces VS Code to reload all type definitions. Do this after installing @types/ packages, modifying tsconfig.json, or adding .d.ts files.

If restarting the TS server doesn’t help, check which tsconfig.json VS Code is using. Open a .ts file and look at the bottom status bar — it shows the TypeScript version and config. Click it to verify it’s pointing at the right config.

tsconfig.json paths not resolving

If you set up path aliases in tsconfig.json and get Cannot find module '@/components/Button':

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

This config only tells TypeScript how to resolve these paths during type checking. Your runtime or bundler also needs to know about them:

  • Vite: Add resolve.alias in vite.config.ts or use vite-tsconfig-paths.
  • Webpack: Add resolve.alias in webpack.config.js or use tsconfig-paths-webpack-plugin.
  • Next.js: Reads tsconfig.json paths automatically. No extra config needed.
  • ts-node / tsx: Use tsconfig-paths:
    npm install --save-dev tsconfig-paths
    node -r tsconfig-paths/register -r ts-node/register src/index.ts

Incremental builds showing stale errors

If you’re using "incremental": true in tsconfig.json, TypeScript caches build info in a .tsbuildinfo file. Sometimes this cache gets stale:

rm -f tsconfig.tsbuildinfo
npx tsc --noEmit

On Windows:

del tsconfig.tsbuildinfo
npx tsc --noEmit

This forces a full rebuild from scratch.

Multiple tsconfig files causing confusion

Large projects often have multiple tsconfig files (tsconfig.json, tsconfig.app.json, tsconfig.node.json). If types work in one context but not another:

  1. Check which config applies to the file throwing the error. In a Vite project, tsconfig.app.json typically covers src/ files and tsconfig.node.json covers vite.config.ts.
  2. Make sure the @types/ package or .d.ts file is referenced in the correct config. Adding @types/node to tsconfig.node.json doesn’t make it available in files governed by tsconfig.app.json.
  3. Each config file needs its own include, types, and typeRoots settings. They don’t inherit from the base config’s sibling files — only from configs referenced via extends.

Type version conflicts

If you see errors like Type 'X' is not assignable to type 'X' where both types appear identical, you likely have duplicate or conflicting type versions. Check:

npm ls @types/react

If multiple versions appear, deduplicate:

npm dedupe

If npm dedupe doesn’t fix it or you’re hitting dependency resolution failures, see Fix: npm ERR! ERESOLVE unable to resolve dependency tree. Or pin to a specific version in package.json:

{
  "devDependencies": {
    "@types/react": "^18.2.0"
  },
  "overrides": {
    "@types/react": "^18.2.0"
  }
}

Related: If you’re getting runtime MODULE_NOT_FOUND errors instead of TypeScript compile errors, see Fix: Error Cannot find module.

Related Articles

Fix: TS2322 Type 'X' is not assignable to type 'Y'

How to fix TypeScript error TS2322 'Type is not assignable to type'. Covers literal types vs general types, string vs String, union types, interface compatibility, generic constraints, readonly arrays, excess property checking, discriminated unions, type assertions, type widening and narrowing, React event handlers, Promise return types, and enum mismatches.

Fix: TS2532 Object is possibly 'undefined' / Object is possibly 'null'

How to fix TypeScript errors TS2532 'Object is possibly undefined', TS18048 'Object is possibly undefined', and 'Object is possibly null'. Covers optional chaining, nullish coalescing, type narrowing, non-null assertion, type guards, strictNullChecks, Array.find, Map.get, React useRef, and more.

Fix: Module not found: Can't resolve / Cannot find module or its corresponding type declarations

How to fix 'Module not found: Can't resolve' in webpack, Vite, and React, and 'Cannot find module or its corresponding type declarations' in TypeScript. Covers missing packages, wrong import paths, case sensitivity, path aliases, node_modules corruption, monorepo hoisting, barrel files, and asset imports.

Fix: [vite] Internal server error: Failed to resolve import

How to fix Vite's 'Failed to resolve import' error, including 'Does the file exist?', 'Optimized dependency needs to be force included', 'Pre-transform error', and '504 (Outdated Optimize Dep)'. Covers missing packages, path aliases, optimizeDeps, cache clearing, and CJS/monorepo edge cases.