皆さん、こんにちは!日本のDevOps・インフラエンジニアです。
今回は、皆さんのコードベースに潜む「デッドコード」、つまり「死んだコード」を見つけ出し、安全に削除するための強力なツール、`ts-prune` についてご紹介します。
1. 導入: なぜデッドコードは問題なのか?
開発を進める中で、機能の追加や削除、リファクタリングを繰り返すのは当然のことです。しかし、その過程で、もはやどこからも参照されなくなったコード、いわゆる「デッドコード」がコードベースに残ってしまうことがあります。
デッドコードは、以下のような問題を引き起こします。
- コードベースの肥大化: 不要なコードが増えることで、全体のコード量が増加し、管理が難しくなります。
- 保守性の低下: 開発者がコードを読む際に、不要なコードに惑わされ、本来追うべきロジックを見失う可能性があります。
- ビルド時間の増加: 不要なコードでもコンパイルやバンドル処理の対象となり、ビルド時間が長くなることがあります。
- 潜在的なバグの温床: 将来的に意図せず修正されてしまい、予期せぬバグを引き起こすリスクもゼロではありません。
`ts-prune` は、こうしたデッドコードを静的解析によって検出し、安全に削除する手助けをしてくれます。これにより、コードベースをスリムに保ち、保守性と開発効率を向上させることができます。
2. 基礎知識: デッドコードと静的解析とは?
デッドコード (Dead Code)
デッドコードとは、プログラムの実行において、決して実行されることのないコードのことです。今回のテーマである「未使用エクスポート」は、デッドコードの一種と言えます。具体的には、他のファイルから `import` されていない `export` された関数、変数、クラス、コンポーネントなどを指します。
静的解析 (Static Analysis)
静的解析とは、プログラムを実行せずに、ソースコードを解析してバグやコーディング規約違反などを検出する手法です。コンパイラも静的解析の一種ですが、`ts-prune` のようなツールは、より広範なコード品質の問題を検出するために特化しています。
`ts-prune` は、TypeScriptの型情報と `import`/`export` の関係性を解析することで、未使用のエクスポートを特定します。
3. 実装/解決策: ts-prune の導入と使い方
`ts-prune` は、npmまたはyarnで簡単にインストールして利用できます。
インストール
npm を使用する場合
npm install –save-dev ts-prune
yarn を使用する場合
yarn add –dev ts-prune
基本的な使い方
プロジェクトのルートディレクトリで、以下のコマンドを実行します。
npx ts-prune
このコマンドを実行すると、`ts-prune` がプロジェクト内のTypeScriptファイルを解析し、未使用のエクスポートを検出してリストアップします。
設定ファイル (ts-prune.config.json)
より詳細な設定を行いたい場合は、プロジェクトのルートに `ts-prune.config.json` ファイルを作成します。
例:
{
“exclude”: [
“src/generated//.ts”, // 自動生成されるファイルなどは除外
“src/types.ts” // 特定のファイルを除外したい場合
]
}
`exclude` オプションを使うことで、解析対象から特定のファイルやディレクトリを除外できます。
CI/CD への組み込み
`ts-prune` をCI/CDパイプラインに組み込むことで、デッドコードが混入するのを防ぐことができます。例えば、GitHub Actionsであれば以下のように設定できます。
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: ’18’
- run: npm install
- run: npm run build # ビルド処理
- run: npx ts-prune # デッドコードチェック
この設定により、`pull_request` が作成された際や `push` された際に自動的に `ts-prune` が実行され、デッドコードがあればビルドが失敗するようになります。
4. サンプルプログラム
ここでは、`ts-prune` がどのようにデッドコードを検出するか、簡単な例を見てみましょう。
まず、以下の3つのファイルを作成します。
`src/utils.ts`
// この関数は他のファイルからインポートされていないため、ts-prune によって検出されるはずです。
export function unusedHelperFunction(): string {
console.log(“これは使われていないヘルパー関数です。”);
return “unused”;
}
// この関数は main.ts からインポートされるため、検出されません。
export function usedHelperFunction(): string {
console.log(“これは使われているヘルパー関数です。”);
return “used”;
}
`src/main.ts`
// usedHelperFunction をインポートします。
import { usedHelperFunction } from ‘./utils’;
function main() {
console.log(“アプリケーションを開始します。”);
const result = usedHelperFunction();
console.log(`ヘルパー関数の結果: ${result}`);
}
main();
`tsconfig.json` (TypeScriptプロジェクトであれば通常存在します)
{
“compilerOptions”: {
“target”: “ESNext”,
“module”: “CommonJS”,
“rootDir”: “./src”,
“outDir”: “./dist”,
“strict”: true,
“esModuleInterop”: true,
“skipLibCheck”: true,
“forceConsistentCasingInFileNames”: true
},
“include”: [“src//.ts”],
“exclude”: [“node_modules”]
}
これらのファイルを作成し、`npm install typescript –save-dev` などでTypeScriptをインストールした後、`npx ts-prune` コマンドを実行してみてください。
`ts-prune` は、`src/utils.ts` 内の `unusedHelperFunction` が `src/main.ts` から `import` されていないことを検出し、以下のような出力が得られるはずです。
src/utils.ts:2:1 – error TS6133: ‘unusedHelperFunction’ is declared but its value is never read. (2300)
このように、`ts-prune` は明確に未使用のエクスポートを指摘してくれます。
5. 応用・注意点
慎重な削除
`ts-prune` が検出したコードは、ほとんどの場合削除して問題ありません。しかし、以下のようなケースでは注意が必要です。
- 意図的にエクスポートされているもの: 例えば、プラグインシステムなどで動的に読み込まれる場合など、静的解析では検知できないパターンも存在します。
- テストコードからの参照: テストコードからのみ利用されている場合、`ts-prune` は「未使用」と判断することがあります。テストファイルを除外する設定や、テスト用のエクスポートであることを示すコメントなどを活用すると良いでしょう。
- 型定義のみのエクスポート: 型定義のみをエクスポートしている場合、`ts-prune` はそれらを参照しているコードがないと「未使用」と判断することがあります。しかし、型定義はコードの実行に直接影響しないため、依存関係がなくなれば削除しても問題ないことが多いです。
`–ignore` オプション
`ts-prune` には `–ignore` オプションもあり、特定のファイルやディレクトリを無視することができます。これは `ts-prune.config.json` の `exclude` と似ていますが、コマンドラインで一時的に指定したい場合に便利です。
npx ts-prune –ignore ‘src/generated//.ts’
コード品質文化の醸成
`ts-prune` は強力なツールですが、最終的にはチーム全体でコード品質に対する意識を持つことが重要です。定期的に `ts-prune` を実行し、検出されたデッドコードを削除する習慣をつけましょう。
いかがでしたでしょうか? `ts-prune` を活用して、皆さんのコードベースをよりクリーンで保守しやすいものにしていきましょう!

コメント