Could not find a declaration file for module 'module-name'.
Complete guide to could not find a declaration file for module 'module-name'.. Covers root causes, diagnostic steps, and working code fixes.
title: 'Fix "Could not find a declaration file for module" in TypeScript' description: 'Resolve the "implicitly has an any type" error by installing @types or creating .d.ts declaration files — step-by-step fix with verification.' excerpt: 'You see "Could not find a declaration file for module X" and "/path/to/file.js implicitly has an any type". Here’s how to fix it reliably — no guesswork.' image: 'https://images.unsplash.com/photo-1547082299-de196ea013d6?auto=format&fit=crop&w=1200&q=80' category: 'TypeScript' tags:
- TypeScript
- Node.js
- troubleshooting date: '2026-06-18' modifiedDate: '2026-06-18' readTime: '8 min read' author: 'Mahdi Br' keywords:
- Could not find a declaration file for module
- implicitly has an any type error
- fix TypeScript module declaration
- TypeScript module resolution troubleshooting
faqSchema:
'@context': 'https://schema.org'
'@type': FAQPage
mainEntity:
- '@type': Question
name: 'Why does TypeScript say "Could not find a declaration file for module"?'
acceptedAnswer:
'@type': Answer
text: 'TypeScript throws this error when it cannot locate type declarations (.d.ts files) for an imported JavaScript module. It happens because the module lacks a
typesfield inpackage.json, or you haven’t installed the corresponding@typespackage from DefinitelyTyped.' - '@type': Question
name: 'How do I fix "implicitly has an any type" for a local module?'
acceptedAnswer:
'@type': Answer
text: 'Create a custom declaration file (e.g.,
src/types/module-name.d.ts) that declares the module with its exports, then ensuretsconfig.jsonincludes thesrc/typesdirectory intypeRootsortypes. For npm packages, install@types/package-nameif available.'
- '@type': Question
name: 'Why does TypeScript say "Could not find a declaration file for module"?'
acceptedAnswer:
'@type': Answer
text: 'TypeScript throws this error when it cannot locate type declarations (.d.ts files) for an imported JavaScript module. It happens because the module lacks a
TL;DR#
If you’re seeing Could not find a declaration file for module 'module-name'. '/path/to/module-name.js' implicitly has an 'any' type, the cause is usually that TypeScript cannot locate type declarations for the imported JavaScript module — either because the package doesn’t ship with types, or you haven’t installed the @types package, or you’re importing a local .js file without a .d.ts declaration.
Fix it by installing @types/module-name (if it exists on DefinitelyTyped) or creating a custom declaration file like src/types/module-name.d.ts that declares the module’s exports.
If that doesn’t work, scroll to verify the fix — there are two common variants this guide also covers.
What you'll see#
Could not find a declaration file for module 'lodash-es'. '/Users/mahdi/project/node_modules/lodash-es/lodash.js' implicitly has an 'any' type.
Try `npm install @types/lodash-es` if it exists or add a new declaration (.d.ts) file containing `declare module 'lodash-es';`It happens when you import a JavaScript module — local or third-party — without type declarations, and TypeScript’s compiler (tsc) runs in strict mode (or noImplicitAny: true). The behavior is the same across Node.js, Next.js, and plain TypeScript projects.
This error appears in three common contexts:
- Third-party JS package (e.g.,
import _ from 'lodash-es'→lodash-eshas notypesfield inpackage.json, and@types/lodash-esis missing). - Local
.jsfile (e.g.,import { formatDate } from '../utils/formatDate'whereformatDate.jshas no siblingformatDate.d.ts). - Custom module (e.g.,
import config from './config.js'in a monorepo whereconfig.jsis not typed).
TypeScript must infer a type for every expression. When it can’t find declarations, it falls back to any, but in strict mode it refuses to do so silently — instead, it errors with this message. The compiler is enforcing type safety, not failing.
Root cause#
TypeScript resolves type definitions for modules in two ways, drawing on TypeScript declaration files: ambient declarations (for global or external modules) and module declarations (for import/export-based modules). When you import something, TypeScript looks for .d.ts files in this order:
- The package’s
typesortypingsfield innode_modules/package-name/package.json. - A corresponding
.d.tsfile in the same directory (e.g.,module-name.d.tsnext tomodule-name.js). - Any
.d.tsfiles in directories listed intypeRoots(default:node_modules/@types). - Custom declaration files referenced in
tsconfig.jsonviatypeRootsortypes.
If none of these exist, TypeScript cannot infer the module’s shape — so it treats it as any, which violates noImplicitAny. Hence the error.
The relevant code path is:
// src/services/apiClient.ts
import { formatDate } from '../utils/formatDate'; // ← triggers error here
export const fetchUser = async (id: string) => {
const date = formatDate(new Date()); // ← `formatDate` is implicitly `any`
return { id, date };
};And formatDate.js:
// src/utils/formatDate.js
export const formatDate = (date) => {
return date.toISOString().split('T')[0];
};TypeScript sees formatDate.js, but no formatDate.d.ts. It doesn’t know formatDate returns a string, so it can’t validate usage — and in strict mode, it refuses to let any slide.
The deeper issue is that TypeScript’s module resolution is opt-in for types. JavaScript packages rarely ship .d.ts files (they’d rather keep package.json minimal), and local JS files never do. So unless you explicitly provide declarations, TypeScript has no way to know the module’s API.
The fix#
The fix depends on whether the module is third-party or local.
For third-party packages, install npm @types packages (@types/<package>) if available:
npm install --save-dev @types/lodash-esFor local modules, create a .d.ts file in src/types/ (or alongside the .js file) and declare the module:
// src/types/formatDate.d.ts
declare module '../utils/formatDate' {
export function formatDate(date: Date): string;
}That single change addresses the cause because TypeScript now has a .d.ts file to consult during resolution — it no longer needs to guess, and it can validate that formatDate takes a Date and returns a string.
Step by step#
- Identify the failing import — check the error message for the exact module path (e.g.,
../utils/formatDate). - Create a declaration file — in
src/types/formatDate.d.ts, add the module declaration. - Ensure TypeScript sees it — update
tsconfig.jsonto includesrc/typesintypeRootsortypes. - Restart the dev server —
tsc --watchornext devwill re-resolve types.
Here’s the full tsconfig.json snippet showing the relevant compiler options to make sure declarations are picked up:
{
"compilerOptions": {
"typeRoots": ["./src/types", "./node_modules/@types"],
"types": ["node"]
},
"include": ["src/**/*"]
}The typeRoots array tells TypeScript to look in ./src/types first, before node_modules/@types. This is critical — otherwise, your custom declarations won’t be found.
Verify the fix#
Run:
npx tsc --noEmitYou should see:
No errors.Instead of:
src/services/apiClient.ts:2:28 - error TS7016: Could not find a declaration file for module '../utils/formatDate'. '/Users/mahdi/project/src/utils/formatDate.js' implicitly has an 'any' type.If you’re using Next.js, restart the dev server:
npm run devThen visit a page that imports the module — the error should be gone from the terminal and browser console.
If you’re still seeing the error, two common variants exist:
Variant A — Module path uses .js extension in import#
TypeScript expects imports without .js extensions in tsconfig.json when moduleResolution: "bundler" or "node16" (Next.js 13+ default), but some tools (like Vite) require .js in imports.
If your error says Could not find a declaration file for module './config.js', but your import is import config from './config.js', TypeScript looks for config.js.d.ts, not config.d.ts.
Fix it by either:
- Removing
.jsfrom the import (import config from './config') and ensuringconfig.d.tsexists, or - Creating
config.js.d.ts(yes, with the.jsin the filename) and declaring:
// src/types/config.js.d.ts
declare module './config.js' {
const config: { api: string; timeout: number };
export default config;
}Variant B — Local module is in node_modules (e.g., symlinked or linked package)#
If you’re developing a local package and linking it with npm link, TypeScript may not resolve its .d.ts files because node_modules resolution skips types fields for linked packages.
Fix it by adding the package’s source directory to typeRoots:
{
"compilerOptions": {
"typeRoots": ["./src/types", "./node_modules/@types", "../my-local-package/src/types"]
}
}Or, better yet, ensure the linked package has "types": "./dist/index.d.ts" in its package.json and build it first.
Why this happens (and how to avoid it next time)#
TypeScript’s strictness is a feature, not a bug — it prevents runtime errors by catching missing types at compile time. But the tradeoff is friction when working with JavaScript modules.
The underlying invariant is: TypeScript only knows what .d.ts files tell it. If a module has no .d.ts, it’s any — and in strict mode, that’s a compile error.
To prevent regressions, adopt these three practices:
-
Install
@typespackages proactively — before importing, checknpm search @typesor visit DefinitelyTyped. If a package has types but isn’t installed, you’ll get this error. -
Use
tsc --noEmitin CI — add it to your linting pipeline. This catches missing declarations before they ship to production. -
Prefer TypeScript-first modules — when building internal packages, ship
.d.tsfiles and set"types": "./dist/index.d.ts"inpackage.json. For local JS files, create asrc/typesdirectory and declare modules there — it’s faster than hunting down errors later.
I cover this in detail in JS to TypeScript: Incremental Migration, No Full Rewrite, where we walk through adding types to legacy JS codebases without rewriting them.
FAQ#
Q: Do I need to install @types/node?
A: Yes — if you’re using Node.js built-ins (fs, path, process), install @types/node as a dev dependency. Without it, imports like import fs from 'fs' will fail with the same error.
Q: Can I disable the error instead of fixing it?
A: You can — by setting "noImplicitAny": false in tsconfig.json — but you shouldn’t. That disables type safety for all modules, not just this one. The correct fix is always to provide declarations.
Q: Why does declare module need the exact path?
A: TypeScript matches declarations by string literal. If your import is import { x } from '../utils/formatDate', the declaration must use declare module '../utils/formatDate' — no trailing .js, no relative path aliases unless you configure them in paths.
Q: What if the module exports a default function?
A: Use export default in the declaration:
declare module '../utils/formatDate' {
export default function formatDate(date: Date): string;
}Then import formatDate from '../utils/formatDate' works with full types.
Related#
- Fix "Property does not exist on Window" in TypeScript
- JS to TypeScript: Incremental Migration, No Full Rewrite
- What is TypeScript and why should I use it instead of JavaScript
Each of these guides extends the same core idea: working with TypeScript's strictness rather than around it, so your code stays correct as your project grows.
One email a month — no fluff
RLS gotchas, Next.js cache debugging, and the one Supabase setting that bit me last month.
Related Guides
How to Convert a String to Number in TypeScript: 2026 Fix
Fix silent NaN errors when converting strings to numbers in TypeScript. Learn explicit parsing, type narrowing, and runtime validation.
TypeScript ! Operator Explained: Fix Object is possibly undefined
What the ! operator does in TypeScript, why it causes "Object is possibly undefined" errors, and how to replace it safely.
Interfaces vs Types in TypeScript: 2026 Best Practices
Clarify when to use interfaces vs types in TypeScript for scalable production apps — with concrete examples and real-world tradeoffs.