Fix TypeScript build errors
TypeScript build errors usually trace to one of a few causes: misconfigured module resolution, duplicate or mismatched @types packages, a strict-flag change, or a genuine type mismatch. Diagnose with `tsc --noEmit` before changing config.
Last verified · Updated May 22, 2026
A TypeScript build error almost always traces to one of four causes: module resolution that does not match how you bundle, duplicate or mismatched @types packages, fallout from a strict-flag change, or a genuine type mismatch. Reproduce with tsc --noEmit and fix the cause — do not paper over it with any or // @ts-ignore.
Symptoms
- Build or CI fails with errors like TS2307, TS2345, or TS2322.
- Editor (tsserver) and command-line
tscdisagree about errors. - Errors appear only after a TypeScript or @types upgrade.
- Imports resolve at runtime but TypeScript reports 'Cannot find module'.
Likely causes
- moduleResolution does not match the bundler (node vs node16 vs bundler).
- Duplicate @types/* packages resolving to conflicting versions.
- A newly enabled strict flag (strictNullChecks, noImplicitAny) surfacing latent bugs.
- Missing type declarations for an untyped dependency.
- isolatedModules requirements not met (e.g. re-exporting a type without
export type).
Diagnostic commands
# Reproduce the exact errors the build sees, without emitting
npx tsc --noEmit
# Print the fully-resolved config tsc is actually using
npx tsc --showConfig
# Find duplicate / mismatched type packages
npm ls typescript
npm why @types/node
npm ls @types/reactCommon error patterns
| Code | Meaning | Typical fix |
|---|---|---|
| TS2307 | Cannot find module 'x' or its type declarations | Install @types/x, add a declarations.d.ts, or fix moduleResolution |
| TS2345 | Argument of type A is not assignable to parameter of type B | Correct the call site or widen/narrow the parameter type — not a cast |
| TS2322 | Type A is not assignable to type B | Fix the assignment or the declared type; check strictNullChecks fallout |
| TS2305 | Module has no exported member 'x' | Check the import name or a version mismatch in @types |
| TS1259 / TS2614 | esModuleInterop / import-shape mismatch | Enable esModuleInterop or switch to a named import |
⚠ skipLibCheck hides errors inside .d.ts files
skipLibCheck: true skips type-checking of declaration files, including your dependencies'. It is a reasonable default for speed, but if errors vanish only because skipLibCheck is on, a duplicate or mismatched @types package is the real problem — fix that rather than relying on the skip.
ℹ tsserver vs tsc disagreements are usually version skew
If your editor reports different errors than
tsc, the editor is probably using a bundled TypeScript while the CLI uses the workspace version. Point the editor at the workspace TypeScript and re-runtsc --noEmitas the source of truth.
AI debugging prompt
My TypeScript build fails. Here is the full output of `npx tsc --noEmit` and `npx tsc --showConfig`: <paste>. For each distinct error code, identify the root cause (module resolution, duplicate @types, strict-flag fallout, missing declarations, or a real type mismatch). Propose the smallest correct fix per group, preferring accurate types over `any` or // @ts-ignore. Flag any error that points to a duplicate @types package and tell me which `npm why` to run.Safety: Do not suggest blanket
any, // @ts-ignore, or disabling strict flags to make the build pass. Each fix must address the underlying cause.
Safe fix workflow
- Reproduce with
npx tsc --noEmitso you fix what the build sees, not the editor. - Group errors by TS code and fix one group at a time.
- For TS2307, decide whether it is a missing @types package, a missing declarations.d.ts, or a moduleResolution mismatch.
- For TS2345/TS2322, fix the type at the source rather than casting; re-run tsc.
- Run
npm whyon any type package that appears in two versions and dedupe. - Re-run
tsc --noEmitafter each group and confirm the error count drops.
Test plan
-
npx tsc --noEmitpasses with zero errors - Unit and integration tests pass on the fixed build
- Production build (
npm run build) succeeds - No new // @ts-ignore or
anywas introduced to silence an error - Editor and CLI report the same result after pointing the editor at the workspace TS
Escalation checklist
- An error persists only because skipLibCheck is on
- A dependency ships broken or duplicated .d.ts files you cannot dedupe
- An error reproduces on one Node/moduleResolution combination only
- A strict-flag change reveals a latent runtime bug needing a code fix, not a type fix
Related upgrade pages
- Migrate JavaScript to TypeScript — Next step forward
- TypeScript 4 to TypeScript 5 Migration Guide — Related path
- TypeScript 5 to TypeScript 6 Migration Guide — Related path
- Upgrade to TypeScript 5 — Next step forward
- Upgrade to TypeScript 6 — Next step forward
Official sources
- TypeScript 5.0 Release Notes — typescriptlang.org (reliability 98%)
- TypeScript Documentation — typescriptlang.org (reliability 98%)
Copy-ready AI prompts
Structured prompts for an AI coding assistant. Inspect first, then execute incrementally, and keep a human in the review loop.
Repo inspection: Repo inspection prompt
You are helping with a TypeScript migration: diagnose and fix TypeScript build errors.
Do not edit files yet. First inspect the repository and report:
1. The exact typescript version in package.json and the lockfile, plus every @types/* package and whether duplicates resolve to different versions (run `npm ls typescript` and `npm why @types/node`).
2. The active tsconfig.json options: strict flags, moduleResolution, target/module, experimentalDecorators, isolatedModules, skipLibCheck, and any flags deprecated in 5.0 / removed in 6.0 (--out, --target ES3, --keyofStringsOnly, --charset, --noImplicitUseStrict).
3. Files using decorators and whether they rely on the legacy (experimentalDecorators) model.
4. The build/typecheck command and whether the project emits with tsc or a bundler.
5. Any // @ts-ignore / // @ts-expect-error suppressions and any JS files type-checked via allowJs/checkJs.
Return: a risk summary, the highest-risk files, a suggested migration order, the commands to run before editing, and any questions that need human confirmation.Safety: Inspection only. The agent must not modify files in this step.
Works with Claude Code, Cursor, GitHub Copilot.
Test failure debugging: Build-error triage prompt
Triage this failing TypeScript build. Input: the full `tsc --noEmit` output and `tsc --showConfig`. Group errors by code (TS2307, TS2345, TS2322, TS2305, TS1259), explain the root cause of each group, and propose the smallest correct fix — accurate types over casts. Call out any error caused by a duplicate @types package and the `npm why` command to confirm it.Safety: No blanket any, // @ts-ignore, or strict-flag disabling. Every fix addresses the underlying cause.
Works with Claude Code, Cursor, GitHub Copilot.
Test plan
Commands
npx tsc --noEmitnpx tsc --showConfignpm run buildnpm test -- --watch=false
Manual checks
- Confirm editor (tsserver) and CLI tsc agree after pointing the editor at the workspace TypeScript.
- Verify that imports flagged TS2307 actually resolve at runtime.
- Re-check any error that only disappears with skipLibCheck enabled.
Regression risks
- Casts or
anyintroduced under deadline that hide real type bugs. - skipLibCheck masking a duplicate @types mismatch.
- moduleResolution change breaking runtime resolution for some dependencies.
Acceptance criteria
tsc --noEmitexits clean with zero errors.- Build and tests pass with no new suppressions.
- All @types/* packages resolve to a single version.
Frequently asked questions
Why does my editor show errors that tsc doesn't (or vice versa)?
Almost always a TypeScript version mismatch: the editor uses its bundled compiler while the CLI uses the workspace version. Point the editor at the workspace TypeScript and treat tsc --noEmit as the source of truth.
Is it ever okay to use skipLibCheck or // @ts-ignore?
skipLibCheck is a fine speed optimization, but if it is the only thing hiding an error you have a duplicate/mismatched @types package to fix. Prefer // @ts-expect-error over // @ts-ignore so suppressions self-clean, and never use either to mask a real type bug.