dunnart
TypeScript · strict migration

Turn on strict
one flag at a time.

dunnart runs every TypeScript --strict sub-flag in isolation and tells you exactly how many errors each one would add. Start with the cheapest. Ship green diffs. Stop staring at 2,000 red squiggles.

★ Star on GitHub
sub-flags analyzed
8
every --strict flag, independently
config required
0
reads your tsconfig.json
runtime deps
1
just typescript
install size
<100KB
excl. typescript

What it looks like

01 / output
~/projects/my-app — dunnart
$ npx dunnart dunnart: analyzing ./tsconfig.json +------------------------------+--------+------------+-------+ | flag | errors | % of total | order | +------------------------------+--------+------------+-------+ | strictNullChecks | 0 | 0.0% | 1 | | strictFunctionTypes | 0 | 0.0% | 2 | | strictBindCallApply | 0 | 0.0% | 3 | | strictPropertyInitialization | 0 | 0.0% | 4 | | noImplicitThis | 0 | 0.0% | 5 | | useUnknownInCatchVariables | 0 | 0.0% | 6 | | alwaysStrict | 0 | 0.0% | 7 | | noImplicitAny | 2 | 100.0% | 8 | +------------------------------+--------+------------+-------+ baseline errors (no strict flags): 0 total new errors across all off flags: 2 suggested: enable flags top-down — smallest delta first.

Why this exists

02 / the problem

The official TypeScript advice for migrating to strict is basically "flip it on and fix the errors." For a greenfield app that's fine. For a 300-file codebase you've been shipping for three years, it's a week-long stall with a PR no reviewer wants to touch.

The truth is that strict is eight independent flags, and they're wildly uneven. noImplicitAny might cost you 400 errors. strictBindCallApply might cost you two. But you can't see that distribution until you've already done the work.

dunnart measures it for you. Once you know which flag is the cheap one, migration stops being a project and starts being a series of small PRs you can land between lunch and standup.

"Turn on strict" is not a task.
"Turn on strictBindCallApply, it's two errors" is a task. — the premise of this tool

What you get

03 / features
01

Exact counts, not estimates

Runs through the real TypeScript compiler API. The numbers are what tsc would tell you — no parsing, no heuristics.

02

Respects your tsconfig

Extends the config you already have. Already enabled some strict flags? They show up as already on ✓ and get skipped.

03

Sorted easiest-first

Rank by delta so you always have an answer to "what's the next small PR I can ship toward strict mode?"

04

JSON output

Pipe --json into a dashboard, a CI check, or a chart tracking your migration progress week over week.

05

Zero config

npx dunnart in the repo root. That's it. No init step, no plugin, no editor extension.

06

One dependency

Just typescript itself. No bundler, no AST library, no magic. Audit it in an afternoon.

Install & use

04 / usage
# one-off npx dunnart # global npm i -g dunnart # requires Node 18+
# default: current directory dunnart # pick a specific tsconfig dunnart --project app/tsconfig.json # machine-readable for dashboards dunnart --json

Honest caveats

05 / read this
  1. i

    Large repos are slow

    Per-flag tsc runs scale with file count × 8 and can take a minute on very large projects. That's the cost of exact counts.

  2. ii

    strictPropertyInitialization is a freeloader

    It requires strictNullChecks to actually emit errors, so its isolated delta is often 0. Its "true" cost is paid once you enable strictNullChecks.

  3. iii

    skipLibCheck is inherited

    dunnart uses your project's tsconfig as-is. Run against a tsconfig with skipLibCheck: true for the cleanest results about your own code.