Code Coverage Testing in TypeScript: How to Stop Guessing and Start Measuring
\n\nImagine you are assembling a complex mechanism with many gears. You are sure you have assembled everything correctly, but as soon as you press the "Start" button, a grinding sound is heard and the mechanism jams. Sound familiar? In the world of TypeScript development, such "mechanisms" are our applications. And code coverage testing is the trial assembly that shows which parts we have checked and which we have left to chance.
\n\nMany developers are skeptical about coverage metrics: "Chasing percentages is evil," "100% coverage does not guarantee the absence of bugs." And this is true. But, like any tool, code coverage can be useful or harmful — it all depends on how you use it. In this article, we will look at how to correctly measure coverage in TypeScript, what tools exist for this, and how not to turn metrics into an end in themselves.
\n\nWhat is Code Coverage and Why TypeScript is No Exception
\n\nCode coverage is a metric that shows which part of the source code was executed during tests. In TypeScript, which compiles to JavaScript, coverage measurement occurs at the level of the compiled code, but modern tools can beautifully display results in terms of the original TS code.
\n\nThe main coverage metrics you need to know:
\n\n- \n
- Line coverage — the percentage of code lines that were executed at least once. \n
- Branch coverage — the percentage of branches (if/else, switch, ternary operators) that were tested. \n
- Function coverage — the percentage of functions/methods that were called. \n
- Statement coverage — the percentage of individual instructions (statements) in the code. \n
For TypeScript projects, branch coverage is especially important, as strict typing does not save you from logical errors in conditions. You can correctly type all variables, but forget about the case when an array is empty, and the function expects at least one element.
\n\nTools for Measuring Coverage in TypeScript
\n\n1. Istanbul (nyc) — The Grandfather of All Coverage
\n\nIstanbul is the most popular tool for measuring coverage of JavaScript and TypeScript code. It works as a standalone utility (via the nyc package) or as a built-in module in test frameworks.
To get started with Istanbul in a TypeScript project, install:
\n\nnpm install --save-dev nyc typescript ts-node\n\nCreate a .nycrc file for configuration:
{\n "extends": "@istanbuljs/nyc-config-typescript",\n "all": true,\n "include": ["src/**/*.ts"],\n "exclude": ["src/**/*.test.ts", "src/**/*.spec.ts"],\n "reporter": ["text", "html", "lcov"],\n "check-coverage": true,\n "branches": 80,\n "lines": 85,\n "functions": 85,\n "statements": 85\n}\n\nRunning tests with coverage:
\n\nnpx nyc mocha --require ts-node/register src/**/*.test.ts\n\nIstanbul generates reports in the console (text) and as HTML pages, where covered code is highlighted in green and uncovered code in red. This is very visual.
\n\n2. Jest — All-in-One
\n\nJest is the most popular test framework for TypeScript. It already includes a built-in coverage tool based on Istanbul. You don't need to install anything extra.
\n\nBasic configuration in jest.config.ts:
import type { Config } from 'jest';\n\nconst config: Config = {\n preset: 'ts-jest',\n testEnvironment: 'node',\n collectCoverage: true,\n coverageDirectory: 'coverage',\n coverageReporters: ['text', 'html', 'lcov'],\n collectCoverageFrom: [\n 'src/**/*.ts',\n '!src/**/*.test.ts',\n '!src/**/*.spec.ts',\n '!src/types/**/*.ts'\n ],\n coverageThresho