TypeScript 型カバレッジを KPI 化:`type-coverage`でチームの型品質を可視化する

TypeScript を導入したプロジェクトで、「型がちゃんと付いているか」を定量的に把握できていますか?コードレビューでは見落としがちな any
型の蔓延や、型定義の抜け漏れは、プロジェクトが大きくなるにつれて深刻な品質問題を引き起こします。
本記事では、type-coverage
という npm パッケージを使って、TypeScript プロジェクトの型カバレッジを数値化し、チームの開発指標(KPI)として活用する方法を詳しく解説します。CI/CD パイプラインへの組み込みから、チーム運用まで、実践的な内容をお届けしますね。
背景
TypeScript における型の重要性
TypeScript の最大の強みは、静的型付けによるコンパイル時のエラー検出です。しかし、実際のプロジェクトでは以下のような問題が発生しがちです。
- 納期に追われて
any
型で逃げてしまう - 外部ライブラリの型定義が不完全で
any
が混入する - チームメンバー間で型に対する意識レベルが異なる
- レガシーコードから段階的に TypeScript 化している途中である
これらの問題を放置すると、TypeScript を導入した意味が薄れてしまいます。
型カバレッジの概念
「型カバレッジ」とは、コードベース全体のうち、どれだけの識別子(変数、関数の引数、戻り値など)に適切な型が付与されているかを示す指標です。テストカバレッジと同様に、パーセンテージで表現されます。
以下の図は、型カバレッジの概念を示しています。
mermaidflowchart TB
codebase["コードベース全体"]
typed["型が付いている識別子"]
untyped["型が付いていない識別子<br/>(any, 暗黙の any など)"]
coverage["型カバレッジ = <br/>typed / (typed + untyped) × 100%"]
codebase --> typed
codebase --> untyped
typed --> coverage
untyped --> coverage
型カバレッジが高いほど、TypeScript の恩恵を最大限に受けられていると言えるでしょう。逆に、カバレッジが低い場合は、型安全性に問題がある可能性が高いです。
なぜ KPI 化するのか
型カバレッジを KPI(重要業績評価指標)として設定することで、以下のメリットが得られます。
# | メリット | 説明 |
---|---|---|
1 | 可視化 | 現状の型品質を数値で把握できる |
2 | 目標設定 | チーム全体で改善目標を共有できる |
3 | 継続的改善 | 定期的な計測で品質の低下を防げる |
4 | 説得力 | ステークホルダーへの説明が容易になる |
5 | モチベーション | 数値の向上がチームのやる気につながる |
特に、リファクタリングや技術的負債の返済を進める際、経営層やプロダクトオーナーに対して「型カバレッジを 80% から 95% に向上させる」といった具体的な数値目標を示せるのは大きな強みです。
課題
型品質の測定が困難
従来、TypeScript プロジェクトで型の品質を測定するには、以下のような方法しかありませんでした。
- コンパイラの警告・エラー数をカウントする(
--strict
オプション使用時) - コードレビューで人力チェックする
- 定期的に全ファイルを目視確認する
しかし、これらの方法には限界があります。
# | 方法 | 課題 |
---|---|---|
1 | コンパイラのエラー数 | エラーがゼロでも any が大量に存在する可能性がある |
2 | コードレビュー | レビュアーの負担が大きく、見落としも発生しやすい |
3 | 目視確認 | 大規模プロジェクトでは現実的ではない |
これらの課題を図で整理すると、以下のようになります。
mermaidflowchart TD
problem["型品質の測定が困難"]
subgraph issues["主な課題"]
issue1["any 型の検出が難しい"]
issue2["定量的な指標がない"]
issue3["チーム全体での共有が困難"]
end
subgraph impacts["影響"]
impact1["型安全性の低下"]
impact2["バグの混入リスク増加"]
impact3["リファクタリングコスト増大"]
end
problem --> issues
issue1 --> impact1
issue2 --> impact2
issue3 --> impact3
CI/CD での自動チェックの欠如
テストカバレッジは CI/CD パイプラインで自動計測され、閾値を下回るとビルドが失敗するように設定されているプロジェクトが多いでしょう。しかし、型カバレッジについては、そのような仕組みが整備されていないケースがほとんどです。
結果として、以下のような問題が発生します。
- プルリクエストで
any
型が混入しても気づかない - 時間の経過とともに型カバレッジが徐々に低下していく
- 後から型を付け直すコストが膨大になる
チーム内での認識のズレ
「型をちゃんと付ける」という基準は、人によって解釈が異なります。ある開発者は as any
を多用し、別の開発者は厳密に型を定義する、といった状況では、コードベースの品質がバラバラになってしまいます。
定量的な指標がないため、チーム内で「何が良い状態か」について共通認識を持つことが難しいのです。
解決策
type-coverage の導入
type-coverage
は、TypeScript プロジェクトの型カバレッジを計測できる npm パッケージです。コードベース全体をスキャンし、型が付いていない箇所を検出して、カバレッジをパーセンテージで報告してくれます。
インストール
Yarn を使ってインストールしましょう。
bashyarn add --dev type-coverage
これで、開発依存関係として type-coverage
がプロジェクトに追加されます。
基本的な使い方
インストール後、以下のコマンドで型カバレッジを計測できます。
bashyarn type-coverage
実行すると、以下のような出力が得られるでしょう。
plaintext2345 / 2500 95.00%
type-coverage success.
この例では、全 2500 個の識別子のうち、2345 個に型が付いており、カバレッジは 95.00% であることを示しています。
詳細な出力オプション
どの箇所に型が付いていないかを確認するには、--detail
オプションを使用します。
bashyarn type-coverage --detail
実行結果の例:
plaintextsrc/utils/helper.ts:12:7 - any
src/components/Button.tsx:45:15 - any
src/api/client.ts:78:3 - any
2345 / 2500 95.00%
これにより、具体的なファイル名、行番号、列番号が表示されるため、修正すべき箇所をピンポイントで特定できます。
型カバレッジの仕組み
type-coverage
は、TypeScript Compiler API を利用してコードを解析し、各識別子の型情報を取得します。以下の図は、その処理フローを示しています。
mermaidflowchart LR
source["ソースコード<br/>(*.ts, *.tsx)"]
ts_api["TypeScript<br/>Compiler API"]
analyze["型情報の解析"]
count["型あり/型なしの<br/>カウント"]
report["カバレッジレポート<br/>(%)"]
source --> ts_api
ts_api --> analyze
analyze --> count
count --> report
この仕組みにより、人手では困難な大規模コードベースの型チェックを、わずか数秒で完了できます。
CI/CD への組み込み
型カバレッジを KPI として活用するには、CI/CD パイプラインで自動計測する仕組みが不可欠です。
package.json へのスクリプト追加
まず、package.json
に専用のスクリプトを追加しましょう。
json{
"scripts": {
"type-check": "tsc --noEmit",
"type-coverage": "type-coverage --at-least 95 --detail"
}
}
ここでは、--at-least 95
オプションを指定しています。これにより、カバレッジが 95% 未満の場合、コマンドがエラー(終了コード 1)を返すようになります。
GitHub Actions での設定例
GitHub Actions を使っている場合、以下のようなワークフローを追加します。
yamlname: Type Coverage Check
on:
pull_request:
branches:
- main
push:
branches:
- main
次に、ジョブの定義を追加します。
yamljobs:
type-coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
続いて、Node.js のセットアップと依存関係のインストールを行います。
yaml- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: yarn install --frozen-lockfile
最後に、型カバレッジのチェックを実行します。
yaml- name: Check type coverage
run: yarn type-coverage
この設定により、プルリクエストが作成されるたびに型カバレッジがチェックされ、閾値を下回るとビルドが失敗するようになります。
GitLab CI での設定例
GitLab CI を使用している場合は、.gitlab-ci.yml
に以下のジョブを追加しましょう。
yamltype-coverage:
stage: test
image: node:18
script:
- yarn install --frozen-lockfile
- yarn type-coverage
only:
- merge_requests
- main
これで、マージリクエスト時に自動的に型カバレッジがチェックされます。
設定ファイルでの詳細制御
type-coverage
は、プロジェクトルートに .type-coverage.json
という設定ファイルを配置することで、より詳細な制御が可能です。
json{
"atLeast": 95,
"strict": true,
"ignoreFiles": [
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/legacy/**/*"
]
}
主な設定項目を以下の表にまとめます。
# | 設定項目 | 説明 |
---|---|---|
1 | atLeast | 最低限必要なカバレッジ(パーセント) |
2 | strict | 厳密モード(暗黙の any も検出) |
3 | ignoreFiles | 除外するファイルのパターン(glob 形式) |
4 | ignoreCatch | catch 句の変数を無視するか |
5 | ignoreUnread | 読み取られない変数を無視するか |
strict オプションの重要性
strict: true
を設定すると、暗黙的な any
型も検出対象になります。例えば、以下のようなコードです。
typescript// 暗黙的な any(関数の引数に型がない)
function greet(name) {
console.log(`Hello, ${name}`);
}
strict モードを有効にすることで、このような見落としがちな型の欠如も検出できるようになります。
ignoreFiles の活用
テストファイルやレガシーコードなど、一時的に型カバレッジの計測から除外したいファイルがある場合、ignoreFiles
を活用しましょう。ただし、除外範囲を広げすぎると本来の目的を見失うため、注意が必要です。
チーム運用での活用方法
型カバレッジを KPI として効果的に活用するには、以下のような運用ルールを設定すると良いでしょう。
段階的な目標設定
いきなり 100% を目指すのは現実的ではありません。現状のカバレッジを確認し、段階的に目標を引き上げていきます。
# | フェーズ | 目標カバレッジ | 期間 |
---|---|---|---|
1 | 現状把握 | 計測のみ | 1 ヶ月 |
2 | 初期改善 | 80% 以上 | 2 ヶ月 |
3 | 中期改善 | 90% 以上 | 3 ヶ月 |
4 | 高品質維持 | 95% 以上 | 継続 |
このように段階を踏むことで、チームへの負担を抑えながら品質向上を実現できます。
プルリクエストでのルール化
新規コードについては、型カバレッジを下げないというルールを設定しましょう。具体的には、以下のようなチェックリストをプルリクエストテンプレートに追加します。
- CI での型カバレッジチェックがパスしていること
- 新規追加したコードには適切な型が付与されていること
- やむを得ず
any
を使用する場合はコメントで理由を明記すること
定期的なレビュー会
月次や四半期ごとに、型カバレッジの推移をチーム全体で振り返る機会を設けるのも効果的です。カバレッジが向上した部分を称賛し、改善が必要な部分について対策を話し合いましょう。
具体例
実際のプロジェクトでの導入事例
ここでは、架空の EC サイトプロジェクトを例に、type-coverage
を導入する流れを見ていきます。
プロジェクトの初期状態
プロジェクト構成は以下の通りです。
plaintextproject-root/
├── src/
│ ├── components/
│ │ ├── ProductCard.tsx
│ │ └── CartButton.tsx
│ ├── api/
│ │ └── client.ts
│ ├── utils/
│ │ └── format.ts
│ └── types/
│ └── index.ts
├── package.json
└── tsconfig.json
まず、現状の型カバレッジを計測してみましょう。
bashyarn type-coverage --detail
結果は以下の通りでした。
plaintextsrc/api/client.ts:23:7 - any
src/components/ProductCard.tsx:15:12 - any
src/utils/format.ts:8:3 - any
src/utils/format.ts:34:5 - any
185 / 230 80.43%
型カバレッジは 80.43% で、4 箇所に any
型が使われていることが判明しました。
問題箇所の特定と修正
src/api/client.ts:23:7
を確認してみます。
typescript// 修正前
export async function fetchProducts() {
const response = await fetch('/api/products');
const data = await response.json(); // ← ここが any
return data;
}
response.json()
の戻り値は any
型になっています。これを適切な型で定義しましょう。
typescript// 型定義の追加
interface Product {
id: number;
name: string;
price: number;
imageUrl: string;
}
次に、関数の戻り値に型を指定します。
typescript// 修正後
export async function fetchProducts(): Promise<Product[]> {
const response = await fetch('/api/products');
const data: Product[] = await response.json();
return data;
}
これで、この関数に関する型の問題が解決しました。
コンポーネントの型修正
src/components/ProductCard.tsx:15:12
を確認します。
typescript// 修正前
interface ProductCardProps {
product: any; // ← ここが any
}
export const ProductCard: React.FC<ProductCardProps> = ({
product,
}) => {
return (
<div className='product-card'>
<h3>{product.name}</h3>
<p>{product.price}円</p>
</div>
);
};
product
プロパティが any
型になっています。先ほど定義した Product
型を使用しましょう。
typescript// 型のインポート
import { Product } from '../types';
typescript// 修正後
interface ProductCardProps {
product: Product;
}
export const ProductCard: React.FC<ProductCardProps> = ({
product,
}) => {
return (
<div className='product-card'>
<h3>{product.name}</h3>
<p>{product.price}円</p>
</div>
);
};
これで、コンポーネントの型安全性が向上しました。
ユーティリティ関数の型修正
src/utils/format.ts
の問題箇所を確認します。
typescript// 修正前
export function formatPrice(price) {
// ← 引数の型がない(暗黙の any)
return `¥${price.toLocaleString()}`;
}
引数と戻り値に適切な型を付与しましょう。
typescript// 修正後
export function formatPrice(price: number): string {
return `¥${price.toLocaleString()}`;
}
これで、関数の入出力が明確になりました。
修正後のカバレッジ確認
すべての修正が完了したら、再度型カバレッジを計測します。
bashyarn type-coverage
結果は以下の通りです。
plaintext230 / 230 100.00%
type-coverage success.
見事に 100% を達成できました。この状態を維持するため、CI/CD に組み込みます。
CI/CD での継続的な監視
GitHub Actions の設定を追加し、プルリクエストごとに型カバレッジをチェックします。
yamlname: Quality Check
on:
pull_request:
branches:
- main
- develop
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Type check
run: yarn type-check
- name: Type coverage check
run: yarn type-coverage
この設定により、以下のフローで品質が担保されます。
mermaidflowchart TD
pr["プルリクエスト作成"]
ci["CI/CD トリガー"]
deps["依存関係インストール"]
typecheck["型チェック<br/>(tsc --noEmit)"]
coverage["型カバレッジチェック<br/>(type-coverage)"]
pass["チェック成功<br/>マージ可能"]
fail["チェック失敗<br/>修正が必要"]
pr --> ci
ci --> deps
deps --> typecheck
typecheck -->|成功| coverage
typecheck -->|失敗| fail
coverage -->|95%以上| pass
coverage -->|95%未満| fail
これにより、型カバレッジが低下するプルリクエストは自動的にブロックされます。
ダッシュボードでの可視化
型カバレッジの推移を可視化するため、CI/CD の実行結果をダッシュボードに表示することも有効です。GitHub Actions であれば、カバレッジバッジを README に追加できます。
まず、カバレッジ情報を JSON 形式で出力します。
bashyarn type-coverage --output-format json > coverage.json
この JSON ファイルを GitHub Actions のアーティファクトとして保存し、外部サービス(Codecov、Coveralls など)と連携することで、視覚的なレポートを生成できます。
以下は、カバレッジの推移イメージです。
mermaidflowchart LR
week1["第1週<br/>80.4%"]
week2["第2週<br/>85.2%"]
week3["第3週<br/>92.7%"]
week4["第4週<br/>95.1%"]
week5["第5週<br/>95.8%"]
week1 --> week2
week2 --> week3
week3 --> week4
week4 --> week5
style week5 fill:#9f9
このように、週次でカバレッジが向上している様子をチーム全体で共有できると、モチベーション向上にもつながります。
レガシーコードへの段階的適用
既存の大規模プロジェクトでいきなり高いカバレッジを達成するのは困難です。その場合、以下のような戦略が有効でしょう。
ディレクトリ単位での適用
まず、新規開発を行うディレクトリのみを対象にします。
json{
"include": ["src/features/**/*"],
"atLeast": 95
}
新機能開発では 95% 以上を必須とし、レガシー部分は別途計画的にリファクタリングします。
段階的な閾値引き上げ
月ごとに閾値を少しずつ引き上げる方法も効果的です。
# | 月 | 閾値 | 実績 |
---|---|---|---|
1 | 1 月 | 80% | 82.3% |
2 | 2 月 | 85% | 87.1% |
3 | 3 月 | 90% | 91.5% |
4 | 4 月 | 95% | 95.8% |
このように、無理のないペースで改善を進めることが、長期的な成功につながります。
まとめ
本記事では、type-coverage
を活用して TypeScript プロジェクトの型カバレッジを KPI 化する方法を解説しました。重要なポイントを振り返りましょう。
まず、型カバレッジは TypeScript の型安全性を定量的に測定する指標であり、テストカバレッジと同様に重要です。type-coverage
を使えば、コードベース全体の型付け状況を数秒で把握できます。
次に、CI/CD パイプラインに組み込むことで、プルリクエストごとに自動チェックが行われ、型品質の低下を未然に防げます。GitHub Actions や GitLab CI での設定例を参考に、ぜひ導入してみてください。
また、チーム運用では段階的な目標設定が鍵となります。いきなり 100% を目指すのではなく、現状を把握した上で、無理のないペースで改善を進めることが大切です。
型カバレッジを KPI として設定することで、チーム全体で型品質への意識が高まり、長期的にメンテナンスしやすいコードベースを構築できます。「型をちゃんと付ける」という曖昧な目標が、明確な数値目標に変わることで、開発体験も向上するでしょう。
ぜひ、あなたのプロジェクトでも type-coverage
を導入して、型品質の可視化に取り組んでみてください。数ヶ月後には、カバレッジ向上の成果をチームで喜び合えるはずです。
関連リンク
- article
TypeScript 型カバレッジを KPI 化:`type-coverage`でチームの型品質を可視化する
- article
TypeScript 公開 API の型設計術:`export type`/`interface`/`class`の責務分担と境界設計
- article
ESLint を Yarn + TypeScript + React でゼロから構築:Flat Config 完全手順(macOS)
- article
TypeScript 型縮小(narrowing)パターン早見表:`in`/`instanceof`/`is`/`asserts`完全対応
- article
TypeScript 共有可能な tsconfig 設計:`tsconfig/bases`で複数パッケージを一括最適化
- article
TypeScript ランタイム検証ライブラリ比較:Zod / Valibot / typia / io-ts の選び方
- article
NestJS クリーンアーキテクチャ:UseCase/Domain/Adapter を疎結合に保つ設計術
- article
WebSocket プロトコル設計:バージョン交渉・機能フラグ・後方互換のパターン
- article
MySQL 読み書き分離設計:ProxySQL で一貫性とスループットを両立
- article
Motion(旧 Framer Motion)アニメオーケストレーション設計:timeline・遅延・相互依存の整理術
- article
WebRTC で遠隔支援:画面注釈・ポインタ共有・低遅延音声の実装事例
- article
JavaScript パフォーマンス最適化大全:レイアウトスラッシングを潰す実践テク
- blog
iPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来