Skip to content

Fix: TypeScript Could not find a declaration file for module (TS7016)

FixDevs ·

Quick Answer

How to fix the TypeScript TS7016 error 'Could not find a declaration file for module' by installing @types packages, creating declaration files, and configuring tsconfig.json.

The Error

You import a third-party package in your TypeScript project and the compiler flags it:

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

This shows up in your editor as a red or yellow squiggly under the import statement. The code still compiles and runs if you have noEmit set to false and strict mode is not enforcing implicit any checks, but the error clutters your editor and blocks CI pipelines that treat warnings as errors.

The TS7016 error is different from TS2307 (“Cannot find module”). TS2307 means TypeScript cannot locate the module at all. TS7016 means TypeScript found the JavaScript code but has no type information for it. The module works at runtime, but TypeScript does not know the shape of its exports.

You see TS7016 with packages that were written in plain JavaScript and never shipped type definitions. You also see it with less popular packages that are not covered by DefinitelyTyped, internal packages in monorepos that lack .d.ts files, and occasionally with packages that do ship types but have a misconfigured package.json.

Why This Happens

TypeScript needs type information for every import. When you write import something from 'some-library', TypeScript does two things:

  1. Resolves the module. It finds the JavaScript file in node_modules/some-library/ using Node module resolution (or whatever moduleResolution is set to in your tsconfig.json).
  2. Looks for type declarations. It checks, in order:
    • A types or typings field in the package’s package.json pointing to a .d.ts file.
    • An index.d.ts file next to the package’s entry point.
    • A matching @types/some-library package in node_modules/@types/.
    • Any .d.ts files included via typeRoots or paths in your tsconfig.json.

If all four checks come up empty, TypeScript raises TS7016. The module’s JavaScript code is there, but TypeScript has no way to describe what something actually is. It falls back to any, and if your configuration disallows implicit any (which strict: true does), the error blocks compilation entirely.

This is a type-system-only problem. Your code is not broken. TypeScript just needs help understanding what the module exports.

Fix 1: Install the @types/ Package

The fastest fix. Many popular JavaScript libraries have community-maintained type definitions on DefinitelyTyped, published under the @types/ scope on npm.

Install the types as a dev dependency:

npm install --save-dev @types/lodash

For scoped packages, replace the / with __:

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

Check if types exist for your package by searching npmjs.com for @types/package-name or running:

npm search @types/some-library

After installing, restart your TypeScript language server (in VS Code: Ctrl+Shift+P > “TypeScript: Restart TS Server”). The error should disappear.

Pro Tip: Not every package needs @types/. Many modern libraries ship their own type definitions. Check the package’s package.json for a types or typings field. If it exists, the package already includes types and an @types/ install is unnecessary. Installing both can cause conflicts where the @types/ version lags behind the actual package version and provides outdated type signatures.

If no @types/ package exists, move to Fix 2.

Fix 2: Create a Custom Declaration File

When there are no published types, you write your own. Create a .d.ts file anywhere in your project that TypeScript can see (inside the directories covered by your include glob in tsconfig.json).

Create a file called src/types/some-library.d.ts:

declare module 'some-library' {
  const content: any;
  export default content;
}

This is the minimum viable declaration. It tells TypeScript “this module exists and its default export is any.” The error goes away, and you lose no type safety beyond what you already had.

For a more useful declaration, describe the parts of the API you actually use:

declare module 'some-library' {
  export function doSomething(input: string): Promise<string>;
  export function formatData(data: Record<string, unknown>): string;
  export const VERSION: string;
}

You do not need to declare every export the library has. Declare only what your code imports. TypeScript will only type-check the parts you describe.

This approach is also necessary for non-JavaScript imports that your bundler handles. If you import CSS modules, images, or other assets:

declare module '*.css' {
  const content: Record<string, string>;
  export default content;
}

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

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

Place these in a src/types/assets.d.ts file and make sure it is included in your TypeScript compilation. If you are working with module resolution issues beyond just type declarations, check the module resolution troubleshooting guide for bundler-specific fixes.

Fix 3: Add typeRoots and types in tsconfig.json

By default, TypeScript automatically picks up all @types/ packages in node_modules/@types/. If you have customized typeRoots or types in your tsconfig.json, you may have accidentally excluded the types you need.

Check your tsconfig.json:

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

The types array is restrictive. When you specify it, TypeScript only loads the listed type packages. If you installed @types/lodash but did not add "lodash" to the types array, TypeScript ignores it.

Two options:

Option A: Remove the types field entirely. This lets TypeScript auto-discover all @types/ packages:

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

Option B: Add the missing type to the array:

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

The typeRoots array controls where TypeScript looks for type packages. If you have custom declaration files in ./src/types/, add that directory to typeRoots. Otherwise, TypeScript only looks in node_modules/@types/.

Common Mistake: Setting typeRoots to ["./src/types"] without including "./node_modules/@types". This tells TypeScript to only look in ./src/types/ for type packages, ignoring all @types/ packages you installed via npm. Always include "./node_modules/@types" in typeRoots if you use any @types/ packages.

Fix 4: Use @ts-ignore or @ts-expect-error as a Temporary Workaround

When you need the error to stop right now and plan to fix it properly later, suppress the error on a per-line basis:

// @ts-expect-error - no types available for some-library
import something from 'some-library';

Or the older directive:

// @ts-ignore
import something from 'some-library';

Prefer @ts-expect-error over @ts-ignore. The difference: @ts-expect-error will warn you when the error no longer exists (e.g., after you install types). @ts-ignore silently suppresses any error on the next line forever, which can hide real problems.

This is a band-aid, not a fix. The import becomes untyped (any), and you lose all IntelliSense and type checking for that module. Use it only when:

  • You are prototyping and do not want to slow down.
  • The library is used in one or two places and you plan to add proper types soon.
  • You are migrating a JavaScript project to TypeScript incrementally.

If you find yourself adding @ts-expect-error to more than a handful of imports, stop and use Fix 2 or Fix 6 instead. Persistent type errors are a sign of deeper configuration problems. For patterns where you hit type assignability errors after suppressing declaration errors, the root cause is usually the same missing type information.

Fix 5: Fix tsconfig Paths and baseUrl Configuration

If the TS7016 error appears on your own modules (not third-party packages), the problem is likely in your tsconfig.json path configuration.

A common setup with path aliases:

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

Common mistakes that cause TS7016 with path aliases:

Missing baseUrl. The paths option requires baseUrl to be set. Without it, TypeScript ignores paths entirely.

Wrong baseUrl relative path. If your tsconfig.json is in the project root and your source is in src/, using "baseUrl": "src" changes all paths to be relative to src/, not the project root.

Glob mismatch. The pattern "@/*": ["./src/*"] maps @/components/Button to ./src/components/Button. If you write @/components/Button.tsx with the extension, TypeScript may not resolve it because it expects to add the extension itself.

The include array does not cover the files. If your tsconfig.json has "include": ["src/**/*"] but your declaration files or source files are outside src/, TypeScript cannot see them.

Verify your configuration by running:

npx tsc --showConfig

This prints the effective configuration after all extends and defaults are applied. Check that baseUrl and paths look correct in the output. If you run into issues where TypeScript cannot find a name that you know exists, path misconfiguration is often the culprit.

Fix 6: Create a Global Declarations File

Instead of creating separate .d.ts files for each untyped module, consolidate them into a single global declarations file. This is practical when you have multiple untyped dependencies.

Create src/global.d.ts:

// Third-party modules without type definitions
declare module 'untyped-library-a';
declare module 'untyped-library-b';
declare module 'legacy-util';

// Wildcard declarations for file types
declare module '*.module.css' {
  const classes: Record<string, string>;
  export default classes;
}

declare module '*.graphql' {
  import { DocumentNode } from 'graphql';
  const value: DocumentNode;
  export default value;
}

// Module with partial type information
declare module 'partially-typed-lib' {
  export interface Config {
    apiKey: string;
    timeout?: number;
    retries?: number;
  }

  export function initialize(config: Config): void;
  export function query(endpoint: string, params?: Record<string, string>): Promise<unknown>;
}

Make sure the file is within the scope of your tsconfig.json. Check the include array:

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

The glob src/**/*.d.ts ensures TypeScript picks up all declaration files in the src directory tree.

A bare declare module 'some-library'; tells TypeScript that the module exists but everything it exports is any. This is functionally identical to Fix 2 but keeps all ambient declarations in one place for easier maintenance.

As your project grows, you can gradually replace bare declarations with typed ones. Start with the modules you use most and where type information provides the most value. Properties that are accessed on untyped modules may trigger property does not exist on type errors if you later add partial types, so plan your type coverage deliberately.

Fix 7: Fix Monorepo Type Resolution Issues

In monorepos (workspaces with Yarn, npm, or pnpm), TS7016 is common because TypeScript cannot find types for sibling packages. The packages exist in the workspace, but TypeScript does not know how to resolve them.

Problem: Package hoisting. Package managers hoist dependencies to the root node_modules/. Your package’s tsconfig.json may not look that far up the tree.

Fix: Use project references. In the consuming package’s tsconfig.json:

{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true
  },
  "references": [
    { "path": "../shared-utils" },
    { "path": "../core-types" }
  ]
}

Each referenced package must also have composite: true and declaration: true in its own tsconfig.json.

Fix: Set up paths for workspace packages:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@myorg/shared-utils": ["../shared-utils/src/index.ts"],
      "@myorg/shared-utils/*": ["../shared-utils/src/*"]
    }
  }
}

This tells TypeScript where to find the source files directly, bypassing npm resolution.

Fix: Check your package manager’s workspace configuration. With pnpm, you may need to add .npmrc settings:

shamefully-hoist=true

Or better, configure pnpm-workspace.yaml to include the right packages and ensure each package’s package.json has correct main, types, and exports fields:

{
  "name": "@myorg/shared-utils",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    }
  }
}

The exports field with a types condition is the modern way to tell TypeScript where declarations live. This requires moduleResolution set to "bundler" or "node16" in your tsconfig.json.

Fix 8: Use skipLibCheck as a Last Resort

If nothing else works and you need the project to compile:

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

This tells TypeScript to skip type-checking all .d.ts files. It does not suppress TS7016 directly, but it prevents errors caused by conflicting or broken declaration files from cascading into your code.

What skipLibCheck actually does:

  • Skips type-checking .d.ts files entirely (both your own and third-party).
  • Speeds up compilation because TypeScript processes fewer files.
  • Hides real errors in declaration files that could cause runtime issues.

When it makes sense:

  • You have conflicting versions of @types/ packages (e.g., @types/react v17 and v18 both installed).
  • A declaration file in node_modules/ has a bug that is not your problem to fix.
  • You are migrating a large codebase and need compilation to succeed while you incrementally add types.

When it does not help: skipLibCheck does not fix TS7016 on its own. If the error is that no declaration exists at all, skipping the check on existing declarations changes nothing. Combine it with Fix 2 or Fix 6 to suppress the specific module errors.

Warning: Do not treat skipLibCheck as a permanent solution. It masks real problems. A broken type declaration that skipLibCheck hides could mean your code passes compilation but crashes at runtime because you called a function with wrong argument types.

Still Not Working?

If you have tried the fixes above and TS7016 persists, check these less obvious causes:

ESM vs CJS Module Type Mismatches

The package publishes ESM-only types but your project uses CommonJS resolution, or vice versa. Check the package’s package.json for a "type": "module" field.

If the package is ESM-only and your tsconfig.json uses "module": "commonjs", TypeScript may not resolve the types correctly. Switch moduleResolution to "bundler" or "node16":

{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler"
  }
}

The "bundler" mode is designed for projects using a bundler like Vite, Webpack, or esbuild. It resolves types the same way your bundler does, eliminating mismatches.

Bundler Module Resolution

Your bundler resolves modules differently from TypeScript’s default Node resolution. Webpack, Vite, and esbuild all have their own resolution algorithms. If a module works at runtime but TypeScript cannot find types for it, the mismatch is between TypeScript’s resolver and your bundler’s resolver.

Set moduleResolution to "bundler" in your tsconfig.json. This aligns TypeScript’s resolution with how modern bundlers work.

Package.json exports Field

Modern packages use the exports field in package.json to control what is importable. If a package defines exports but does not include a types condition, TypeScript cannot find the declarations even if .d.ts files exist in the package.

Check the package’s package.json:

{
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  }
}

If the types condition is missing, the package author needs to add it. As a workaround, use Fix 2 to declare the module manually.

TypeScript Version Mismatch

Older versions of TypeScript (pre-4.7) do not support the exports field or the "bundler" module resolution strategy. If you are on an older TypeScript version, upgrade:

npm install --save-dev typescript@latest

Then update your tsconfig.json to use the newer resolution settings.

Verify Your Fix Worked

After applying any fix, always verify:

npx tsc --noEmit

This runs the type checker without producing output files. If there are no errors, the fix worked. If TS7016 still appears, check that you are editing the correct tsconfig.json (some projects have multiple: tsconfig.json, tsconfig.build.json, tsconfig.app.json) and that the file is being compiled by the right configuration.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles