tsc TS2307: Cannot find module 'X' or its type declarations (missing @types) in CI
TS2307 here means the JavaScript package resolves at runtime, but it ships no bundled types and the matching @types/X stub is not installed, so tsc has no declarations to type-check against.
What this error means
tsc fails with "error TS2307: Cannot find module 'X' or its corresponding type declarations" for a third-party library that imports and runs fine in Node, but has its types in a separate DefinitelyTyped package.
src/server.ts:1:21 - error TS2307: Cannot find module 'express' or its corresponding type declarations.
1 import express from 'express';
~~~~~~~~~Diagnose it: which tsconfig and which compiler?
A TypeScript error that appears only in CI usually means the runner is compiling with a different config or a different compiler version than your editor. Your editor uses the workspace TypeScript and the nearest tsconfig.json; CI uses whatever the lockfile resolved and whatever config the build script names.
# what CI will actually use
npx tsc --version
npx tsc --showConfig | head -40
# which files are in the program (a missing include is a common cause)
npx tsc --listFiles | wc -l
# type-check only, no emit, same as most CI gates
npx tsc --noEmitCommon causes
The library ships no types and @types is a devDependency only
Packages like express keep their declarations in @types/express. If that stub is missing from the CI install (for example it was a devDependency skipped by npm ci --omit=dev), tsc cannot find types.
A lockfile that omits the @types package
The runtime dependency was added without its @types counterpart, so npm ci installs the library but not the declarations.
How to fix it
Install the matching @types stub
- Add the DefinitelyTyped package for the library to devDependencies.
- Commit the updated lockfile.
- Ensure CI installs dev dependencies (do not pass
--omit=dev) when it runs tsc.
npm install --save-dev @types/express
npm ci # without --omit=dev so @types is presentInstall dev deps before type-checking
Type stubs live in devDependencies, so the type-check job must install them. A production-only install removes the types tsc needs.
- run: npm ci
- run: npx tsc --noEmitPin the compiler so unrelated updates cannot break the gate
TypeScript adds errors in minor releases. An unpinned compiler turns a routine dependency update into a red build on code nobody touched, which is the most common false alarm in a TypeScript CI pipeline.
// package.json
{
"devDependencies": {
"typescript": "5.6.3" // exact, not ^5.6.3
}
}How to prevent it
- Add the
@types/*stub whenever you add a library that has no bundled types. - Keep
@typespackages in devDependencies and install dev deps in the type-check job. - Commit the lockfile so the same stub versions install in CI.