TS7016: Could not find a declaration file for module (fix)
TS7016 fires when you import an untyped JavaScript module under noImplicitAny. The right fix is usually `npm i -D @types/X` — but sometimes the package already ships types, and sometimes you need to write a one-line declaration.
You import a perfectly normal npm package and TypeScript stops you:
Could not find a declaration file for module 'some-lib'.
'.../node_modules/some-lib/index.js' implicitly has an 'any' type.
Try `npm i --save-dev @types/some-lib` if it exists or add a new
declaration (.d.ts) file containing `declare module 'some-lib';`This is TS7016. TypeScript even prints its own two suggested fixes. This guide explains when each is right, plus the case the message doesn't mention: the package may already ship types.
Why it happens#
TS7016 fires when all three are true:
- You import a module that resolves to a plain JavaScript file with no bundled
.d.ts, and - there is no
@types/Xpackage installed, and noImplicitAnyis on (it is, understrict).
Without type information the module would silently become any. The noImplicitAny docs put it plainly: with the flag on, "TypeScript will issue an error whenever it would have inferred any." So TS7016 is the protection working — not a broken install.
Fix 1 (preferred) — Install the DefinitelyTyped types#
npm install --save-dev @types/some-libHow to know it exists: DefinitelyTyped publishes type packages to npm under the @types scope with the same name as the underlying package (react → @types/react). Per the handbook, "TypeScript automatically finds type definitions under node_modules/@types, so there's no other step needed." If the install errors with 404, no community types exist — go to Fix 3.
Fix 2 — Check if the package already ships types#
Sometimes TS7016 is misdiagnosed: the package does bundle types and you're chasing a phantom. Look in the dependency's package.json for a types (or its synonym typings) field:
{
"main": "./lib/main.js",
"types": "./lib/main.d.ts"
}If a package bundles types but you still see TS7016, suspect a stale install, a typesVersions mismatch for your TS version, or an exports map that doesn't expose the .d.ts. The last one has its own wording. We reproduced it on 1 October 2026 with TypeScript 5.9.3: a package whose top-level types field points to ./types/index.d.ts but whose exports map only lists ./dist/index.js:
error TS7016: Could not find a declaration file for module 'libx'. '/c/node_modules/libx/dist/index.js' implicitly has an 'any' type.
There are types at '/c/node_modules/libx/types/index.d.ts', but this result could not be resolved when respecting package.json "exports". The 'libx' library may need to update its package.json or typings.It appeared under moduleResolution nodenext and bundler, which read exports and ignore the top-level types field once exports is present. Switching back to the legacy node10 resolution silenced it on TypeScript 5.9, but TypeScript 7 rejects that setting outright (error TS5108: Option 'moduleResolution=node10' has been removed), so it is not a fix to rely on. The real fix belongs to the library: a types condition inside exports (".": { "types": "./types/index.d.ts", "default": "./dist/index.js" }) made the same import compile cleanly in our test. Until the library ships that, use a local declaration (Fix 3) and report the issue upstream.
A related variant: the mismatch appears right after bumping TypeScript itself —
npm install typescript@latestbreaks the build withCannot find module '@types/node'orProperty 'auth' does not exist on SupabaseClient. That's not a missing-types issue but amodule/moduleResolutiondrift between the compiler and@types/node; the dedicated guide to aligning TypeScript and @types/node covers realigning both in one pass.
Fix 3 — Write a local declaration#
When neither @types/X nor bundled types exist, declare the module yourself. Create a file like src/types/some-lib.d.ts. The minimal "make it any" form (TypeScript's own second suggestion):
// src/types/some-lib.d.ts
declare module 'some-lib';Better — a typed stub keeps real safety instead of opting the whole module into any:
declare module 'some-lib' {
export function doThing(input: string): string;
export interface Options {
retries?: number;
timeout?: number;
}
export const version: string;
}The .d.ts must be inside your tsconfig include scope, or TypeScript won't pick it up. If it's ignored, check include/files in tsconfig.
Last resort — turn off the check#
// silences ALL of these, project-wide
{ "compilerOptions": { "noImplicitAny": false } }Or // @ts-ignore on the import line. Both work and both are bad:
- The package ships ESM-only types but your
moduleResolutionisnode16/nodenext/bundlerand itsexportsmap hides the.d.ts— that's a resolution problem, not a missing-types one. - Your
@types/Xversion drifted from the runtime package version — reinstall to match, or you'll get wrong types rather than missing ones.
Decision guide#
| Check | Result | Do this |
|---|---|---|
npm i -D @types/X succeeds | Community types exist | Done |
Package's package.json has types/typings | It ships its own | Reinstall / fix resolution |
| Neither exists | Truly untyped | declare module 'X'; (+ a typed stub) |
| Nothing else and you're in a hurry | — | @ts-ignore (last resort) |
Official references: Consuming declaration files, Type declarations, module .d.ts template, noImplicitAny.
TS7016 in a pnpm or Yarn PnP monorepo#
TypeScript looks for @types packages in the node_modules folder next to the importing file and in every parent folder. What changes between package managers is which packages end up in those folders. If adding all of node_modules to typeRoots produces TS2688 errors across ordinary runtime packages, correct the overly broad typeRoots instead of installing declarations for every reported name.
With npm workspaces, dependencies are hoisted to the root node_modules, so an @types/some-lib declared by any workspace package is visible to all of them. pnpm does not hoist that way: a workspace package's node_modules holds only what its own package.json declares, and the pnpm documentation presents this strictness as deliberate. We tested both on 1 October 2026 (pnpm 12.8.1, TypeScript 5.9.3), with lodash imported from packages/api under strict:
@types/lodash declared only in a sibling package (packages/web):
npm workspaces -> no error (hoisted to the root node_modules)
pnpm -> error TS7016: Could not find a declaration file for module 'lodash'.
'/p/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/lodash.js' implicitly has an 'any' type.
@types/lodash declared in the root package.json (pnpm add -D -w @types/lodash):
pnpm -> no errorSo the pnpm symptom is: the types are installed somewhere in the repo, often in the package that was set up first, and the package that imports the library cannot see them. A root-level install is visible to every workspace package, because the root node_modules is a parent folder of all of them. The cleanest fix is to declare the types in the workspace package that imports the library, next to the library itself:
# from the monorepo root, targeting one workspace package
pnpm add -D @types/some-lib --filter apiYarn Plug'n'Play removes node_modules entirely in favour of a .pnp.cjs resolution map built from each package's declared dependencies, so the same rule applies there: declare the @types package in the workspace that imports the library.
When @types is installed but the version has drifted#
Installing @types/X fixes TS7016 immediately, but DefinitelyTyped versions its type
packages to track the major.minor version of the underlying library (its README explains the scheme) —
nothing keeps them in sync automatically once both are installed. A package.json that
pins some-lib@4 alongside a stale @types/some-lib@2 can resurface a related error
(Property does not exist, or a fresh TS7016 if the major-version folder structure
changed enough that the old types no longer match) that looks identical to a missing
install but isn't fixed by reinstalling the same thing again — the same version-drift
shape covered for @types/node itself in the guide to realigning TypeScript and @types/node.
Two commands settle it before guessing:
npm ls @types/some-lib # what you actually have installed
npm view @types/some-lib versions --json | tail -5 # what DefinitelyTyped currently shipsIf the installed major version trails the runtime package's major version, upgrade the
types package explicitly (npm install -D @types/some-lib@latest) rather than
reinstalling the runtime dependency — the runtime install was never the problem. The
inverse also happens: a library that used to need @types/X sometimes starts shipping
its own bundled types in a later major release, which makes the separate @types
package not just unnecessary but a source of duplicate/conflicting declarations — worth
uninstalling once the package's own package.json types field confirms this happened.
Further reading: Fix TS2305: Module Has No Exported Member in TypeScript, Fix "Property does not exist on Window" in TypeScript.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Continue Reading
Fix TS2305: Module Has No Exported Member in TypeScript
TS2305 says the export you're importing doesn't exist under that name. The cause is almost always one of: a typo, default-vs-named confusion, a CJS/ESM interop mismatch, or @types drifting from the runtime package. Each has a precise fix.
Fix Cannot find type definition file for 'body-parser'
Why one broken folder under node_modules/@types fails the whole project, why restarting VS Code sometimes clears it, and what TypeScript 6.0 changed.
Module resolves to an untyped module: fix TS2665 in .d.ts
Why a hand-written declaration for an untyped package fails with "cannot be augmented", why the same block works in a .d.ts but not a .ts file under module node16 to nodenext, and the one-line move that fixes it.


