mcpField
T
type-coverage

type-coverage

github.com/marius-townhouseTesting & quality643 installsUpdated 38w ago
Repository

About type-coverage

A TypeScript skill for measuring the share of symbols with concrete types rather than any, and monitoring it over time. It helps teams migrating JavaScript or maintaining type safety set thresholds and catch regressions in CI.

Key features

  1. 01Measures typed-symbol coverage
  2. 02Identifies symbols typed as any
  3. 03Supports minimum coverage thresholds
  4. 04Tracks changes and prevents regressions

Use cases

  1. 01Monitoring type safety during JavaScript migration
  2. 02Checking coverage in code review
  3. 03Failing CI when coverage falls below a threshold
  4. 04Prioritizing any-type cleanup

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/marius-townhouse/effective-typescript-skills --skill type-coverage

After installing, type/type-coveragein Claude Code to confirm it loaded.

Details

From the project README

Track Your Type Coverage to Prevent Regressions in Type Safety

Overview

Monitor how much of your code is typed vs any.

Type coverage measures the percentage of symbols with real types vs any. Track it over time to prevent type safety regressions.

When to Use This Skill

  • Migrating JavaScript to TypeScript
  • Maintaining type quality over time
  • Code reviews for type safety
  • Measuring progress on any elimination

The Iron Rule

What gets measured gets managed.
Track type coverage; set coverage goals.

Remember:

  • any spreads silently through code
  • Coverage can regress without notice
  • Explicit tracking prevents decay
  • Set team goals for coverage improvement

Understanding Type Coverage

let x: number = 1;        // x is covered (has real type)
let y: any = 2;           // y is NOT covered (has any)
let z = JSON.parse('{}'); // z is NOT covered (implicit any from JSON.parse)

Type coverage = (covered symbols) / (total symbols)

Tools for Measuring Coverage

type-coverage package
npm install -g type-coverage
type-coverage --detail

Output:

23384/24058 97.20%

With --detail, it shows which symbols have any:

src/api.ts:15:7 - data
src/utils.ts:42:3 - result
Project-Specific Configuration
// package.json
{
  "scripts": {
    "type-coverage": "type-coverage --at-least 95"
  }
}

Fail CI if coverage drops below threshold.

Sources of any

1. Explicit any
function process(data: any) { ... }  // Developer wrote any
2. Implicit any (when noImplicitAny is off)
function process(data) { ... }  // data is implicitly any
3. any from Libraries
const data = JSON.parse(str);   // Returns any
const result = $.ajax(url);     // jQuery returns any
4. Contagious any
function getUser(): any { ... }
const user = getUser();
//    ^? any - spreads from function

const name = user.name;
//    ^? any - continues spreading

Strategies for Improvement

Replace JSON.parse
// Before: returns any
const data = JSON.parse(str);

// After: validate with zod
const schema = z.object({ name: z.string() });
const data = schema.parse(JSON.parse(str));
//    ^? { name: string }
Fix Library Types
// Augment JSON.parse to return unknown
declare global {
  interface JSON {
    parse(text: string): unknown;
  }
}
Use unknown Instead
// Before
function parse(): any { ... }

// After
function parse(): unknown { ... }
Add Type Annotations
// Before: inferred as any from library
const result = externalLib.process(data);

// After: explicitly typed
const result: ProcessedData = externalLib.process(data);

Tracking Over Time

# Record in CI
echo "$(date): $(type-coverage)" >> coverage-history.txt

# Fail if coverage decreased
type-coverage --at-least $(cat .type-coverage-baseline)

Setting Team Goals

MilestoneCoverage Target
Migration start50%
Phase 175%
Phase 290%
Stable95%+

Increase targets as codebase matures.

Preventing Regressions

Pre-commit Hook
# .husky/pre-commit
type-coverage --at-least 95
CI Check
# .github/workflows/ci.yml
- name: Type Coverage
  run: npx type-coverage --at-least 95
Code Review Checklist
  • No new any types without justification
  • Type coverage didn't decrease
  • External data is validated

Dealing with Necessary any

Sometimes any is unavoidable:

// Document why any is needed
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const legacy: any = oldSystem.getData();  // TODO: Type when migrating legacy system

Track these with comments and tickets.

Real-World Example

// Before migration: 60% coverage
// Sources of any:
// - JSON.parse: 15%
// - Legacy API: 12%
// - Untyped dependencies: 8%
// - Explicit any: 5%

// Action plan:
// 1. Add zod validation: +10%
// 2. Type legacy API responses: +10%
// 3. Add @types packages: +8%
// 4. Remove explicit any: +5%

// After: 93% coverage

Pressure Resistance Protocol

1. "We Can't Achieve 100%"

Pressure: "Some code can't be typed"

Response: Aim for improvement, not perfection. Track what you can.

Action: Set realistic goals; document necessary exceptions.

2. "It's Too Much Work"

Pressure: "Fixing all any types takes too long"

Response: Incremental improvement. Block new any types first.

Action: Ratchet: prevent new any, fix old over time.

Red Flags - STOP and Reconsider

  • Coverage decreasing over time
  • New any types without justification
  • any spreading from function returns
  • Untested code with heavy any usage

Common Rationalizations (All Invalid)

ExcuseReality
"It's just one any"any spreads; one becomes many
"We'll fix it later"Later never comes without tracking
"Coverage is high enough"Set higher goals as you improve

Quick Reference

# Measure coverage
npx type-coverage

# With details
npx type-coverage --detail

# Fail if below threshold
npx type-coverage --at-least 95

# In package.json
"scripts": {
  "type-coverage": "type-coverage --at-least 95"
}

The Bottom Line

Track type coverage to prevent regression.

any types spread silently. Without measurement, type safety erodes over time. Use tools to track coverage, set goals, and fail builds when coverage drops.

Reference

Based on "Effective TypeScript" by Dan Vanderkam, Item 49: Track Your Type Coverage to Prevent Regressions in Type Safety.

Comments

Markdown supported