TS2688Compiler Error
Since TS 2.0

Fix TS2688: Cannot Find Type Definition File

Learn why TypeScript throws TS2688 when a name in types, typeRoots or a reference directive has no declaration file, and how to fix your tsconfig.

error TS2688: Cannot find type definition file for 'X'

What This Error Means

TS2688 means you asked TypeScript to load a type package by name and it could not find the declarations for that name. The name came from one of three places: the types array in tsconfig.json, a /// <reference types="..." /> directive at the top of a file, or the automatic scan of every folder under typeRoots.

This is a resolution failure in the ambient type system, not a failed import. import { readFile } from "fs" is a module specifier and fails with TS2307 when it cannot be resolved. "types": ["node"] is a request to pull a whole declaration file into the global scope of every file in the program — no import statement anywhere. When that request comes up empty, you get TS2688, and the message names the package, not any source file of yours.

error TS2688: Cannot find type definition file for 'jest'.
                                                  ~~~~~~
  The file is in the program because:
    Entry point of type library 'jest' specified in compilerOptions

Modern TypeScript prints that second block, and it is the most useful part of the diagnostic: it tells you who asked. specified in compilerOptions means your types array. Entry point for implicit type library means nobody asked — the compiler found a folder under typeRoots and tried to load it on its own. Those two causes have completely different fixes, so read that line before changing anything.

Two things that do not help, because both are frequently tried first: skipLibCheck only skips checking declaration files that exist, so it has no effect here, and exclude does not apply to typeRoots scanning.

Common Causes

1. A Package Named In types That Is Not Installed

The most common shape by far. A starter template ships a types array, someone removes the test runner or never installs it, and the array keeps naming it. CI hits this constantly when a job installs production dependencies only.

// ❌ Broken — tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "types": ["jest", "node"]
  }
}
error TS2688: Cannot find type definition file for 'jest'.
  The file is in the program because:
    Entry point of type library 'jest' specified in compilerOptions
error TS2688: Cannot find type definition file for 'node'.
  The file is in the program because:
    Entry point of type library 'node' specified in compilerOptions

Note that the error fires even though no file in the project mentions jest. The types array is evaluated before any of your code is looked at.

# ✅ Fixed — install the declarations the array asks for
npm install --save-dev @types/jest @types/node
// ✅ Fixed — or drop the entry, if the project genuinely does not use it
{
  "compilerOptions": {
    "strict": true,
    "types": ["node"]
  }
}

Pick whichever matches reality. If orderTotal.test.ts calls describe and expect, you need the package. If the test runner was swapped for Vitest two refactors ago, the entry is dead weight and deleting it is the honest fix.

2. A Stray Folder Under typeRoots

Leave types out of your config and TypeScript switches to automatic mode: it loads every immediate subfolder of every typeRoots directory. That default is ./node_modules/@types, which is normally full of nothing but type packages. Point typeRoots somewhere less disciplined and every folder there becomes a load request.

// ❌ Broken — tsconfig.json, no "types" array, so everything under ./types loads
{
  "compilerOptions": {
    "strict": true,
    "typeRoots": ["./types"]
  }
}
types/
  order-schemas/
    index.d.ts          ← a real type package
  build-output/
    main.js             ← build artefacts, no declarations
 
error TS2688: Cannot find type definition file for 'build-output'.
  The file is in the program because:
    Entry point for implicit type library 'build-output'

build-output was never mentioned in any config or any file. The folder existing next to a real type package was enough. The same thing happens with a node_modules/@types/babel__core directory left half-written by a failed install, and with typeRoots: ["./"], which asks the compiler to treat .github, dist and src as type packages.

// ✅ Fixed — point typeRoots only at directories that hold type packages
{
  "compilerOptions": {
    "strict": true,
    "typeRoots": ["./node_modules/@types", "./src/types"]
  }
}

If the offending folder is inside node_modules/@types, the folder itself is the bug: rm -rf node_modules package-lock.json && npm install rebuilds the tree and the phantom package disappears with it.

3. typeRoots Overridden So node_modules/@types Is No Longer Searched

typeRoots replaces the default, it does not extend it. The moment you add a directory for your own hand-written globals, every @types package stops being findable — including the ones your types array names.

// ❌ Broken — order-schemas lives in node_modules/@types, which is now unsearched
{
  "compilerOptions": {
    "strict": true,
    "typeRoots": ["./src/types"],
    "types": ["order-schemas", "legacy-globals"]
  }
}
error TS2688: Cannot find type definition file for 'order-schemas'.
  The file is in the program because:
    Entry point of type library 'order-schemas' specified in compilerOptions

legacy-globals resolves fine — it sits in ./src/types. Only the package that moved out of reach fails, which is what makes this one confusing to read: the config looks like it works, because half of it does.

// ✅ Fixed — keep the default root first, then add your own
{
  "compilerOptions": {
    "strict": true,
    "typeRoots": ["./node_modules/@types", "./src/types"],
    "types": ["order-schemas", "legacy-globals"]
  }
}

Order matters for shadowing, not for resolution: with ./node_modules/@types first, a published package wins over a local folder of the same name. Most projects never need typeRoots at all — a .d.ts file anywhere inside include is already part of the program.

4. A reference types Directive For A Package This Workspace Lacks

Triple-slash directives are the third entry point, and they travel: a file copied between workspaces brings its /// <reference types="vite/client" /> with it, into a package where vite is not a dependency.

// ❌ Broken — src/apiClient.ts, in a workspace without vite installed
/// <reference types="vite/client" />
//                   ~~~~~~~~~~~~~
// Error: Cannot find type definition file for 'vite/client'.
 
export const apiBaseUrl: string = import.meta.env.VITE_API_BASE_URL
// Error: Property 'env' does not exist on type 'ImportMeta'.

The second error is the tell: TS2688 is never alone for long. Whatever globals the missing package declared are now undeclared too, so the failure cascades into TS2339, TS2304 or TS2503 on every line that used them. Fix the 2688 and the rest usually vanish in one pass.

// ✅ Fixed — after `npm install --save-dev vite` in this workspace
/// <reference types="vite/client" />
 
export const apiBaseUrl: string = import.meta.env.VITE_API_BASE_URL

In a monorepo, check whether the directive belongs in a shared base tsconfig.json that every package extends. If the Node CLI package inherits "types": ["vite/client"] from the root, the fix is not to install Vite there — it is to move that entry down into the web package that actually uses it.

How to Fix It

  1. Read the "The file is in the program because" block. It tells you which of the three entry points asked for the name: specified in compilerOptions points at your types array, Entry point for implicit type library means a folder under typeRoots got picked up automatically, and a file-and-line means a /// <reference types> directive. Each has a different fix, and guessing wastes a build cycle.

  2. Install the package, or delete the name. For a real dependency, npm install --save-dev @types/<name> — or the package itself, when it ships its own declarations, as vite and cypress do. For a leftover entry from a template, remove it from types. Do not add an empty src/types/<name>/index.d.ts to make the message go away: it silences the error and types the whole package as nothing, so the globals you wanted stay missing and the next error is TS2304.

  3. Keep ./node_modules/@types first in typeRoots, or omit typeRoots entirely. The option replaces the default rather than adding to it, which breaks every @types package at once. Most projects do not need it — a .d.ts file inside include already contributes its globals, no type-package folder structure required.

  4. Clean out folders that are not type packages. Anything sitting under a typeRoots directory needs an index.d.ts or a package.json with a types field. rm -rf node_modules package-lock.json && npm install clears failed-install debris; for your own directories, move build output and config folders somewhere the scan does not reach.

  5. Run npx tsc --showConfig when the config looks fine but the error persists. It prints the fully resolved configuration after every extends is applied, which is the only reliable way to see a types or typeRoots value inherited from a shared base config. Then keep the array honest: pin the types list to what the project actually uses, so a dependency removed next quarter fails loudly at review time instead of on a CI machine.

FAQ

What causes TypeScript error TS2688?

TS2688 is a name lookup that came up empty. TypeScript resolves type packages by name from three places — the types array in tsconfig.json, a /// <reference types="..." /> directive, and the automatic scan of every subfolder under typeRoots — and each name must resolve to an index.d.ts or a package.json with a types field. When one does not, you get this error. It is the ambient-declaration counterpart to TS2307: that one is about a module you imported, this one is about a declaration bundle you asked to be loaded globally, with no import involved anywhere in your code.

How do I fix Cannot find type definition file for 'jest' or 'node'?

Decide first whether the project uses those globals. If your tests call describe and expect, or your code touches process.env and Buffer, install the declarations:

[object Object]

If the entry is a leftover — the runner was replaced, or the array was copied from a template — delete that name from types instead. Both fixes are legitimate; what is not legitimate is creating an empty stub directory to satisfy the lookup, because the program then compiles without the globals it needs and fails one error later with TS2304.

Why does TS2688 name folders I never referenced?

Because omitting types turns on automatic inclusion. With no explicit array, TypeScript loads every immediate subfolder of every typeRoots directory as a type package, and a folder with no declarations in it fails that load. That is how build-output, .github or a partially installed babel__core end up in your error log without appearing in a single config file. The diagnostic labels these Entry point for implicit type library, as opposed to specified in compilerOptions. Two ways out: point typeRoots at directories that contain only type packages, or set an explicit types array — which switches off the automatic scan entirely, so only the names you list are ever loaded.

Related Errors

Practice This

Browse all TypeScript practice challenges to keep sharpening your type-level skills.

Share this reference

Become a TypeScript Pro

Track your progress through 100+ hands-on challenges. Free, sign in with GitHub.

Or start solving right away: explore all TypeScript challenges