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:
- Bundled types. The package itself ships a
.d.tsfile (look for atypesortypingsfield in itspackage.json). Most modern packages do this. - DefinitelyTyped. Community-maintained type definitions published as
@types/package-nameon npm. This covers popular packages that don’t ship their own types. - Your own declaration files. A
.d.tsfile 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.jsonis misconfigured. Theinclude,exclude,typeRoots, ortypessettings 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
moduleResolutionsetting 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/nodeFor multiple packages:
npm install --save-dev @types/node @types/react @types/expressCommon @types/ packages
| Package | Types Package | What it covers |
|---|---|---|
| Node.js built-ins | @types/node | process, Buffer, __dirname, require, fs, path, etc. |
| React | @types/react | useState, useEffect, JSX types, component types |
| React DOM | @types/react-dom | createRoot, render, hydrate |
| Express | @types/express | Request, Response, NextFunction, router types |
| Jest | @types/jest | describe, it, expect, mock types |
| Mocha | @types/mocha | describe, it, before, after |
| Lodash | @types/lodash | All lodash utility function types |
| jQuery | @types/jquery | $, DOM manipulation types |
| Cors | @types/cors | CORS middleware types |
| Cookie Parser | @types/cookie-parser | Cookie parser middleware types |
| Supertest | @types/supertest | HTTP assertion library types |
| UUID | @types/uuid | UUID generation function types |
How to check if @types/ exists for a package: Search on npm:
npm search @types/package-nameOr 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/orsrc/@types/— a dedicated types directory inside your source root.- Project root — alongside
tsconfig.json. - Any directory listed in
includein yourtsconfig.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"
}
}| Value | When 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) — includesPromise,Map,Set,Array.prototype.at(), etc.DOM— includesdocument,window,HTMLElement,fetch, etc. Omit this for Node.js-only projects.DOM.Iterable— includes iterable DOM types likeNodeListiteration.
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:
Your
@types/reactversion must match your React version. React 18 needs@types/react@18.x. React 19 bundles its own types — remove@types/reactentirely.Set
jsxcorrectly intsconfig.json:{ "compilerOptions": { "jsx": "react-jsx" } }Using
"react-jsx"(or"react-jsxdev") means you don’t needimport 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:
- Check
includeintsconfig.json. The.d.tsfile must be in a matched path. - Check
exclude. Make sure it’s not excluded. - The file must have the
.d.tsextension, not.ts. A regular.tsfile withdeclare moduleworks differently from a.d.tsfile — it’s treated as a module, not an ambient declaration. - 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:
- Open the command palette (
Ctrl+Shift+P/Cmd+Shift+P). - 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.aliasinvite.config.tsor usevite-tsconfig-paths. - Webpack: Add
resolve.aliasinwebpack.config.jsor usetsconfig-paths-webpack-plugin. - Next.js: Reads
tsconfig.jsonpathsautomatically. 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 --noEmitOn Windows:
del tsconfig.tsbuildinfo
npx tsc --noEmitThis 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:
- Check which config applies to the file throwing the error. In a Vite project,
tsconfig.app.jsontypically coverssrc/files andtsconfig.node.jsoncoversvite.config.ts. - Make sure the
@types/package or.d.tsfile is referenced in the correct config. Adding@types/nodetotsconfig.node.jsondoesn’t make it available in files governed bytsconfig.app.json. - Each config file needs its own
include,types, andtypeRootssettings. They don’t inherit from the base config’s sibling files — only from configs referenced viaextends.
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/reactIf multiple versions appear, deduplicate:
npm dedupeIf 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.