The Error
You're mid-refactor or just pulled a branch and suddenly your entire IDE goes red:
Cannot find module './Component' or its corresponding type declarations. ts(2307)
The build fails. Nothing compiles. You check the file โ it's there. You check the import โ it looks right. What gives?
TypeScript can't resolve the module you're trying to import. The file might exist on disk but TypeScript can't "see" it, or the types are missing entirely. Rule out each cause one by one โ there are at least five distinct scenarios.
Quick Diagnosis
Before touching anything, figure out which scenario you're in:
- The file exists but TypeScript still complains โ path or extension issue
- Importing an npm package โ missing
@typespackage - Importing a non-TS file (CSS, SVG, JSON) โ missing module declaration
- Just installed a package โ tsconfig or node_modules issue
- Monorepo or path aliases โ tsconfig paths misconfiguration
Fix 1: Check the File Path and Extension
The classic 2 AM mistake: a wrong path. TypeScript is case-sensitive on Linux and macOS. Windows is more forgiving โ which makes case bugs extra sneaky when code works locally but breaks in CI.
// Wrong โ file is actually 'Button.tsx'
import Button from './button';
// Correct
import Button from './Button';
Also check for a missing directory index:
// If Component is a directory with index.tsx
import Component from './Component'; // resolves to ./Component/index.tsx
import Component from './Component/index'; // explicit
For .tsx files, make sure your tsconfig has JSX support:
{
"compilerOptions": {
"jsx": "react-jsx"
}
}
Fix 2: Missing @types Package for npm Modules
Third-party packages like lodash or express often ship only JavaScript โ no bundled types. TypeScript doesn't know what to do with them.
Cannot find module 'lodash' or its corresponding type declarations. ts(2307)
Install the corresponding @types package:
npm install --save-dev @types/lodash
# or
yarn add -D @types/lodash
# or
pnpm add -D @types/lodash
After installing, restart your TypeScript server in VS Code: Ctrl+Shift+P โ TypeScript: Restart TS Server. Skipping this step is responsible for a surprising number of "still broken" reports.
To check if a types package exists before installing:
npm search @types/your-package-name
Fix 3: Declare the Module Yourself
No @types package? You'll need to write the declaration yourself. Create src/declarations.d.ts (or src/global.d.ts) and add:
// Minimal โ tells TS "trust me, this exists"
declare module 'some-untyped-package';
// Better โ add types if you know the shape
declare module 'some-untyped-package' {
export function doSomething(input: string): void;
export default function main(): void;
}
Static assets need declarations too. SVGs, CSS modules, and images all require explicit module declarations or TypeScript will refuse to import them:
// src/declarations.d.ts
declare module '*.svg' {
const content: string;
export default content;
}
declare module '*.css' {
const styles: Record;
export default styles;
}
declare module '*.png' {
const src: string;
export default src;
}
Fix 4: Fix tsconfig.json Module Resolution
Wrong resolution strategy means TypeScript looks in the wrong places. This trips up a lot of projects migrating to ESM or switching bundlers.
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
}
}
Which moduleResolution to pick:
"bundler"โ for Vite or webpack projects (TypeScript 5.0+)"node16"or"nodenext"โ for Node.js with native ESM"node"โ classic CommonJS, older projects
Two other settings that catch people off guard: esModuleInterop: true is required for default imports from CommonJS packages. resolveJsonModule: true is required for import data from './data.json'. Also verify your source files actually fall inside the include or rootDir paths.
Fix 5: Path Aliases Not Resolving
Path aliases like @/components/Button are convenient until they silently break. The gotcha: tsconfig paths only affect type checking. Your bundler has no idea about them unless you configure it separately.
Step 1 โ add to tsconfig.json:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
Step 2 โ mirror it in your bundler. For Vite:
// vite.config.ts
import { defineConfig } from 'vite';
import path from 'path';
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
});
For webpack:
// webpack.config.js
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
};
Fix 6: Nuke node_modules and Reinstall
Botched installs and lockfile conflicts leave node_modules in a half-broken state. The package appears installed but the files are corrupt or mismatched. This is the nuclear option โ blunt, but it works about 80% of the time when nothing else makes sense.
rm -rf node_modules
rm package-lock.json # or yarn.lock / pnpm-lock.yaml
npm install
Restart the TS server afterward.
Fix 7: Check the declarations.d.ts Is Included in tsconfig
Created a .d.ts file but TypeScript still ignores it? The file needs to be inside a directory that tsconfig's include already covers โ or listed explicitly:
{
"include": [
"src/**/*",
"src/declarations.d.ts"
]
}
The simplest fix: just drop the .d.ts file anywhere inside src/ and tsconfig will pick it up automatically.
Verify the Fix
Run the TypeScript compiler in check-only mode โ no output files, just type errors:
npx tsc --noEmit
# Clean output = no errors
In VS Code, the red squiggles should vanish after restarting the TS server. Still showing errors while tsc --noEmit passes clean? That's a VS Code cache issue, not a real error. Close the workspace and reopen it.
Still Stuck? Trace the Resolution
When all else fails, turn on verbose resolution logging. This dumps every path TypeScript checked and exactly where it gave up:
npx tsc --noEmit --traceResolution 2>&1 | grep -A5 "Module name '.*Component'"
Noisy output, but it's the definitive debugger for ts(2307). You'll see lines like Loading module as file/folder and File '.../Component.ts' does not exist โ which tells you exactly which directory TypeScript is searching and why it's coming up empty.

