33.7 Measuring Progress: Counting any Usages and Coverage
Right, so you’ve started the migration. You’ve got tsc running, you’ve silenced the most egregious errors with a few any bandaids, and now you’re staring at a question: “Are we there yet?” The answer, my friend, is almost certainly “no,” but we can at least figure out how far away ’there’ is. We need metrics that tell a true story, not a fairy tale. Relying on the TypeScript compiler’s error count is like measuring a road trip by how many times you’ve screamed at other drivers—dramatic but not terribly useful. Let’s talk about real, actionable metrics.
The Deceptive Allure of any
First, we need to understand the enemy. any is the cheat code of TypeScript. It tells the compiler, “I got this, buddy, just look the other way.” It’s useful for a quick fix, but it’s a hole in your type safety net. A codebase with 1000 lines of perfectly typed code and 10 lines of any has a hole big enough to drive a bus through. Your goal isn’t to get zero compiler errors; it’s to get zero implicit any and as few explicit anys as possible.
The most basic metric is simply counting the number of any usages in your codebase. You can do this with a simple grep, but that’s crude. It counts comments and doesn’t give you context. A much better way is to use TypeScript’s own API via a dedicated tool.
# Install it globally or as a dev dependency
npm install -g typescript-count-types
# Run it on your project
count-types --includeAny --project tsconfig.json
This will spit out a raw number. Seeing that number go down over time is satisfying. But a raw count is blind. Is that any in a third-party type definition you can’t control, or is it in the core of your application’s state management? You need to know where they are.
Generating an any Usage Report
To get a real sense of the problem, you need a report. My tool of choice here is typescript-any-report. It gives you a breakdown that’s actually useful.
npx typescript-any-report
This will traverse your project and produce a list of every any usage, organized by file. The output looks something like this:
File: src/utils/legacyHelpers.ts
- Line 42: Variable: `userData`
- Line 58: Function return type: `getOldFormatData`
File: src/components/WeirdOldComponent.js (converted)
- Line 15: Parameter: `props`
Now you have a battle plan. You can sort these files by importance and start systematically replacing any with concrete types. Tackle the core utility files and state modules first; fixing one any there might automatically fix a dozen inferred any errors elsewhere.
The Other Side of the Coin: Type Coverage
Counting any tells you about the negative space—the parts missing types. But what about the positive space? How much of your code is actually typed? This is where type coverage comes in. It’s a concept popularized by the library type-coverage.
# Install the library
npm install --save-dev type-coverage
# Run it on your project
npx type-coverage
This tool uses the TypeScript language server to analyze every identifier in your code (variables, parameters, return types, etc.) and counts how many of them have an explicit type or a type that can be perfectly inferred (like const x = 5 inferring to 5, not number).
The output will be something like: 41598 / 42005 99.03% meaning 99.03% of your identifiers are typed. That sounds great, right? Well, don’t pat yourself on the back just yet. The initial percentage for a newly migrated large codebase is often deceptively high because TypeScript is brilliantly good at inference. The real value of this tool isn’t the headline number; it’s the list of untyped identifiers it can generate.
npx type-coverage --detail
This will produce a list of every single identifier that lacks a type. Many will be benign, but buried in that list you’ll find the real culprits: function parameters that defaulted to any because you forgot to type them, or variables that were initialized with null and never properly typed. This detailed report is your punch list for moving from “mostly typed” to “rigorously typed.”
Why These Metrics Matter Together
Using these two metrics in tandem gives you a complete picture. any-count shows the active problems you’ve created (or inherited). type-coverage shows the passive holes—the places where you thought you had types but actually don’t. Watching the any count trend downward and the coverage trend upward is the closest you’ll get to a quantifiable feeling of progress in this grueling process. It turns a vague, overwhelming task into a series of concrete, fixable bugs. And that, frankly, is the only way any of this gets done.