TypeScriptの「files」プロパティを再考する:巨大なコードベースを制御下に置くための外科的アプローチ
TypeScriptのプロジェクトが成長し、数万行、あるいは数十万行の規模に達したとき、多くのエンジニアが直面するのが「コンパイル時間の増大」と「IDEの反応速度の低下」です。
`tsconfig.json`における `include` や `exclude` は、言わば「広域指定」の絨毯爆撃です。しかし、今日語りたいのは、より鋭利なメスのような存在、すなわち `files` プロパティです。
なぜ、いまさら `files` なのか。それは、大規模アプリケーションにおける「ビルドの決定論的性質(Determinism)」と「メモリ管理」を極限まで最適化するためです。
—
絨毯爆撃から外科手術へ:`files` プロパティの真価
`files` は、コンパイル対象とするファイルを配列で直接指定する設定です。`include` との決定的な違いは、ワイルドカード(globパターン)を一切許容しないという点にあります。
一見すると、「毎回ファイル名を書くなんて非効率だ」と思われるかもしれません。しかし、巨大なモノレポ環境や、複雑な依存関係を持つライブラリのコア部分においては、この「明示性」こそが最強の武器になります。
なぜ `files` がパフォーマンスに直結するのか
TypeScriptコンパイラ(`tsc`)は、プログラムを解析する際に、依存関係にあるすべてのファイルを再帰的に探索します。`include` で巨大なディレクトリを指定していると、コンパイラは `node_modules` やテストファイル、あるいは一時的に生成された型定義ファイルまでを、予期せぬタイミングで「型推論の対象」としてメモリに読み込んでしまうことがあります。
これが、IDEのホバー遅延や、ホットリロードの鈍化を招く主犯です。
`files` を使用することで、コンパイラは「ここからスタートして、これだけを解析すればいい」という明確なパスを手にします。これにより、コンパイラのAST(抽象構文木)生成コストを物理的に制限し、メモリ使用率を劇的に抑えることが可能になります。
—
実践:モジュール境界を保護する構成
大規模なプロジェクトでは、ドメイン層とインフラ層の境界が曖昧になりがちです。以下は、コアロジックを確実に保護し、不要なコンパイル負荷を排除する `tsconfig.json` の構成例です。
{
“compilerOptions”: {
“target”: “ESNext”,
“module”: “NodeNext”,
“strict”: true,
“skipLibCheck”: true
},
// includeを空、あるいは最小限にし、filesで制御する
“include”: [],
“files”: [
// アプリケーションの単一エントリーポイントを明示
“src/index.ts”,
// 依存関係を明示的に引き込むための型定義ファイル
“src/types/global.d.ts”,
// 特定のコアモジュールのみを先に型チェックの対象にする
“src/core/domain/user-aggregate.ts”
]
}
なぜこれが「重大なバグ」を防ぐのか
もし `include` で `src//` のような指定をしていると、本来テスト用であるはずのダミーデータや、モッククラスまでが、いつの間にかプロダクションコードの型解決に紛れ込むリスクがあります。
`files` を使えば、「このファイルが読み込まれていない=このコードはアプリから見えていない」 という事実をコンパイラが保証してくれます。これは、意図しない循環参照や、本来分離されるべきレイヤー間の汚染を、ビルドタイムの型エラーとして即座に可視化することを意味します。
—
アーキテクチャの観点からの最適化:非同期競合とメモリ効率
大規模なWebアプリケーションにおいて、非同期処理の競合や型定義の衝突は、開発体験(DX)を殺す最大の要因です。
特に、CI/CDパイプラインにおいて「なぜかローカルでは通るのにCIで落ちる」というケースの多くは、`tsconfig` の解釈が環境によって微妙に揺らぐことに起因します。`files` を用いることで、解析対象を確定させることは、CIの実行時間を安定化させる(=キャッシュ効率を最大化する) ことと同義です。
- メモリ効率: 不要な型定義の解析を排除し、LSP(Language Server Protocol)のメモリ消費を抑制。
- レンダリング負荷: WebpackやViteといったビルドツールに渡す前の段階で、`tsc` が処理するASTのサイズを最小化することで、型チェックのボトルネックを解消。
—
結論:スペシャリストとしての賢い使い分け
誤解しないでほしいのですが、すべてのプロジェクトで `files` を使うべきだと言っているわけではありません。小〜中規模のプロジェクトであれば `include` で十分です。
しかし、あなたが「型安全性」と「ビルド速度」の狭間で苦しんでいるなら、一度立ち止まって `files` を試してみてください。
1. コアロジック(ドメイン層)のみを `files` に記述する
2. それ以外を `include` で管理し、コンパイルの「外枠」として扱う
このハイブリッド戦略こそが、数万行を超えてもなお、淀みのない高速な開発環境を維持するための、プロフェッショナルの矜持です。
コンパイラに任せるのではなく、コンパイラをコントロールする。そのための最小かつ最強の手段が、この `files` プロパティなのです。次に `tsconfig.json` を開くとき、ぜひその「制御の快感」を体感してみてください。

コメント