Skip to content

Repository files navigation

๐Ÿฉบ tsconfig-doctor

Score your tsconfig's strictness and catch its footguns โ€” extends chain and all.

npm version CI types license

Your tsconfig.json says "strict": true, so you're safe โ€” right? Except noUncheckedIndexedAccess (the flag that makes arr[i] return T | undefined) isn't part of strict, your module / moduleResolution are a mismatched pair that mis-resolves ESM imports, allowJs is on but checkJs is off so your JS is never type-checked, and the strict flag you think you have is actually turned back off three files up the extends chain.

TypeScript has 100+ compiler options and no tool that grades your config. tsconfig-doctor resolves the whole extends chain into the effective config, scores its strictness, and flags every missing safety flag and contradiction โ€” locally, deterministically, with the exact fix.

npx tsconfig-doctor scan
tsconfig.json  53/100 (F) ยท strictness 4%
  โœ—       `strict` mode is off                                   strict
  โš        noUncheckedIndexedAccess is off                        noUncheckedIndexedAccess
  โš  L6    Modern `module` with legacy `moduleResolution`         footgun.module-resolution
  โš  L7    allowJs is on but checkJs is off                       footgun.allowjs-no-checkjs
  โ„น L4    Legacy compile target (es5)                            footgun.legacy-target

Why tsconfig-doctor?

  • ๐Ÿงฎ It grades your config, not a preset. @tsconfig/strictest is a preset to copy; tsc --showConfig dumps the effective config with no judgment. Neither tells you which safety flags you're missing or which settings contradict.
  • ๐Ÿ”— It follows extends. Relative paths, extends arrays (TS 5.0+), and packages like @tsconfig/strictest โ€” resolved through node_modules into one effective config, so it catches a strict flag disabled in a base you inherited.
  • ๐ŸŽฏ Every finding has the exact fix. Not "consider strictness" โ€” the precise option to add and why it matters (with the failure it prevents).
  • ๐Ÿ”’ Local & deterministic. No network, no API key. Drop it in CI and the build fails the moment a PR weakens strict or drops noUncheckedIndexedAccess.

Why not ask an LLM "is my tsconfig strict"? It can't resolve your real extends chain across node_modules, can't run on every PR, and option interactions (strict โ†’ 8 flags, module/moduleResolution pairing) are exact rules, not a guess.

Install

# run it now, from your project root
npx tsconfig-doctor scan

# or add it
npm install -g tsconfig-doctor      # global CLI
npm install -D tsconfig-doctor      # CI dependency

Node โ‰ฅ 18. With no arguments it audits ./tsconfig.json.

Quick start

tsconfig-doctor scan                                  # audit ./tsconfig.json
tsconfig-doctor scan packages/app/tsconfig.json       # a specific file
tsconfig-doctor scan --min-score 80                   # CI gate
tsconfig-doctor scan --md tsconfig-report.md          # Markdown for a PR comment
tsconfig-doctor scan --allow noUnusedLocals,noUnusedParameters
tsconfig-doctor init                                  # write a config

See examples/sample-report.md, and examples/strict.tsconfig.json for a config that scores an A.

What it checks

Group Examples
Strictness strict and its 8 family flags (strictNullChecks, noImplicitAny, โ€ฆ) โ€” including any you disabled under strict
Extra safety noUncheckedIndexedAccess (the big one strict omits), noImplicitReturns, noFallthroughCasesInSwitch, noImplicitOverride, exactOptionalPropertyTypes, unused locals/params
Interop & modules esModuleInterop, forceConsistentCasingInFileNames, isolatedModules, verbatimModuleSyntax
Footguns module/moduleResolution mismatch, allowJs without checkJs, noEmit with declaration/composite, composite without declaration, verbatimModuleSyntax vs deprecated flags, legacy target

Each finding is a weighted error / warning / info; the file rolls up to a 0โ€“100 score, an Aโ€“F grade, and a strictness % (how much of the recommended rubric weight you've achieved).

Real scenarios

1. Stop strictness regressions in CI. A PR that flips strict off, or disables strictNullChecks "just to ship", fails the gate:

# .github/workflows/ci.yml
- run: npx tsconfig-doctor scan --min-score 90

2. Audit a monorepo's packages at once. Point it at every package tsconfig and see which ones quietly inherit a loose base:

tsconfig-doctor scan packages/*/tsconfig.json --md report.md

3. Harden a project you inherited. npx tsconfig-doctor scan gives you a prioritized checklist โ€” the exact flags to add, hardest-hitting first.

Configuration

tsconfig-doctor init writes tsconfig-doctor.config.json:

{
  "ignore": [],     // rule/option ids to skip entirely
  "allow": [],      // options you've intentionally left off (e.g. ["noUnusedLocals"])
  "minScore": 0     // CI gate threshold
}

Library API

import { analyzeTsconfigFile, resolveTsconfig, DEFAULT_CONFIG } from "tsconfig-doctor";

const report = analyzeTsconfigFile("tsconfig.json", DEFAULT_CONFIG);
console.log(report.score, report.strictness, report.findings);

// Or just resolve the effective config yourself:
const { options } = resolveTsconfig("tsconfig.json");

Also exported: analyzeResolved (pure), RUBRIC, STRICT_FAMILY, parseJsonc, and types.

Roadmap

  • ๐Ÿค– Optional --ai layer (bring-your-own key) to explain a finding's impact on your code or draft the migration. The core stays 100% offline and deterministic.
  • A --fix mode that writes the safe, additive flags into your tsconfig.
  • TS-version-aware defaults (some defaults changed across releases).
  • More footguns (paths without baseUrl, jsx without jsxImportSource, lib/target mismatch).
  • A web playground โ€” paste a tsconfig, see the audit, nothing uploaded.

๐Ÿ’– Sponsor

tsconfig-doctor is free and MIT-licensed, built and maintained in spare time. If it hardened your types, please consider supporting it:

  • โญ Star this repo โ€” the simplest free way to help others find it.
  • ๐Ÿ‹ Sponsor via Lemon Squeezy โ€” one-time or recurring.

License

MIT ยฉ tsconfig-doctor contributors

About

Audit tsconfig.json for strictness & footguns โ€” resolves the extends chain, scores the effective config, flags missing safety flags (noUncheckedIndexedAccess) and contradictions (module/moduleResolution mismatch). Deterministic CLI, JSON/MD reports.

Topics

Resources

Code of conduct

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages