TypeScriptにおいてtsconfig.jsonは、プロジェクトの挙動を決定づける最重要のファイルです。

単にソースコードをJavaScriptに変換する際のルールを決めるだけでなく、型の厳格さ、モジュール解決の手法、そして開発体験(DX)の質を左右する土台となります。

近年のJavaScriptエコシステムでは、ESModules(ESM)の完全な普及やランタイムの多様化が進んでおり、現代的な開発環境に合わせた適切な設定を理解することは、堅牢なアプリケーションを構築する上で欠かせません。

この記事では、モダンなTypeScript開発に最適な設定構成とその各オプションの詳細を深く掘り下げて解説します。

tsconfig.jsonの役割と基本構造

tsconfig.jsonは、TypeScriptコンパイラ(tsc)がプロジェクトをどのように処理するかを指示するための設定ファイルです。

このファイルが存在するディレクトリがTypeScriptプロジェクトのルートとして認識されます。

設定ファイルの生成と基本構成

新しいプロジェクトを開始する際、最も一般的な方法は以下のコマンドを実行することです。

Shell
# tsconfig.jsonの初期化
npx tsc --init

このコマンドを実行すると、膨大な数の設定項目がコメントアウトされた状態で生成されます。

基本的な構造は大きく分けて以下の4つのセクションで構成されます。

  1. compilerOptions:コンパイルの挙動や型チェックの強度を指定する中心的なセクション。
  2. include:コンパイル対象に含めるファイルやディレクトリを指定。
  3. exclude:コンパイル対象から除外するものを指定(通常は node_modules など)。
  4. extends:他の設定ファイルを継承し、共通設定を使い回すために使用。

モダンな開発では、これらすべてをゼロから記述するのではなく、ベースとなる推奨設定を継承しつつ、プロジェクト固有の要件に合わせて微調整する手法が一般的です。

モダンな開発に必須の主要オプション

現代のTypeScript開発において、特に重要視されるオプションを分類して解説します。

言語機能と出力ターゲットの設定

まずは、TypeScriptをどのバージョンのJavaScriptに変換し、どのようなモジュールシステムを利用するかを定義します。

target

targetは、出力されるJavaScriptのバージョンを指定します。

2020年代後半の現在では、古いブラウザ(IEなど)を考慮する必要がほとんどなくなったため、ES2022ESNext を指定するのが一般的です。

JSON
{
  "compilerOptions": {
    "target": "ES2022" // クラスフィールドやTop-level awaitが利用可能なバージョン
  }
}

module と moduleResolution

ここが最も混乱を招きやすいポイントですが、モダンなプロジェクトでは以下の組み合わせが推奨されます。

オプション推奨値理由
moduleNodeNext (または Node16)モダンなNode.jsのESM挙動に準拠するため
moduleResolutionNodeNext (または Node16)型定義の検索アルゴリズムを最新のNode.jsに合わせるため

NodeNextを指定することで、package.jsonの “type”: “module” 設定を正しく解釈し、適切な拡張子(.js / .mjs / .cjs)の扱いが可能になります。

厳格な型チェックの設定

TypeScriptの真価を発揮させるためには、strict モードを有効にすることが大前提です。

strict

"strict": true を設定すると、以下の複数の厳格化オプションがすべて有効になります。

  • noImplicitAny:型推論に失敗して暗黙的に any になった場合にエラーを出す。
  • strictNullChecksnullundefined を厳格に区別する。
  • strictFunctionTypes:関数の引数の型チェックを厳格化する。

新規プロジェクトでは必ず true に設定すべき項目です。

2026年基準の推奨設定構成例

現代的なフルスタック開発やライブラリ開発でベースとなる設定例を提示します。

アプリケーション開発(Node.js / ESM中心)

JSON
{
  "compilerOptions": {
    /* 基本設定 */
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ES2022", "DOM", "DOM.Iterable"], 
    
    /* 型チェック */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    
    /* エミット(出力)設定 */
    "outDir": "./dist",
    "sourceMap": true,
    "removeComments": true,
    
    /* 相互運用性とその他 */
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "verbatimModuleSyntax": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "**/*.test.ts"]
}

verbatimModuleSyntax の重要性

近年導入された verbatimModuleSyntax は、import/exportの扱いをより予測可能にするためのオプションです。

これを true にすると、型のみのインポートは必ず import type を使うことが強制され、ランタイムコードに不要なインポートが残るのを防ぎます。

詳細オプションの深掘り

モジュール解決と相互運用性

esModuleInterop

CommonJSモジュールをESMスタイルでインポートする際に発生する不整合を解消します。

例えば、import React from 'react' のような記述を可能にします。

モダンな開発では true が標準です。

forceConsistentCasingInFileNames

ファイル名の大文字小文字を厳格に区別します。

Windows(区別しない)とLinux/macOS(区別する)での開発環境の差異によるビルド失敗を防ぐために true に設定します。

パフォーマンスとビルドの最適化

skipLibCheck

型定義ファイル(.d.ts)のチェックをスキップします。

これを true にすることで、外部ライブラリ内の型エラーに悩まされることなく、自分のプロジェクトのコードのみに集中でき、コンパイル時間も短縮されます。

incremental

true に設定すると、前回のコンパイル情報をファイルに保存し、変更があった箇所のみを再コンパイルします。

大規模なプロジェクトでの開発効率を劇的に向上させます。

プロジェクト構造を管理する include, exclude, extends

設定を整理し、メンテナンス性を高めるための機能を活用しましょう。

extends による設定の共有

複数のパッケージを持つモノレポ構成や、会社全体で共通のルールを適用したい場合、extends を利用します。

JSON
// tsconfig.base.json
{
  "compilerOptions": {
    "strict": true,
    "target": "ES2022",
    "skipLibCheck": true
  }
}

// プロジェクト直下の tsconfig.json
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./build"
  },
  "include": ["src"]
}

パスエイリアスの設定(paths)

深い階層のディレクトリからファイルをインポートする際、../../../../components/Button のような記述は可読性を下げます。

paths オプションを使うことで、これを解決できます。

JSON
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"]
    }
  }
}

これにより、コード内では以下のように記述可能になります。

TypeScript
// 修正前
import { Button } from "../../../components/Button";

// 修正後(エイリアス利用)
import { Button } from "@/components/Button";

注意点として、TypeScript自体はパスの解決を行いますが、実行時のJavaScriptでこのパスを解釈できるようにするには、ViteやWebpack、あるいはNode.jsのSubpath Imports(package.jsonのimportsフィールド)との同期が必要です。

トラブルシューティング:設定が反映されない場合

tsconfig.json を変更したのに、エディタ上のエラーが消えない、あるいはビルド結果が変わらないという場面に遭遇することがあります。

  1. エディタのTSサーバー再起動:VS Codeなどのエディタを使用している場合、コマンドパレットから TypeScript: Restart TS Server を実行してください。
  2. 対象ファイルの確認:そのファイルが本当に include の対象に含まれているか、あるいは exclude されていないかを確認します。
  3. 複数のtsconfigの競合tsconfig.node.json など、ツールチェーン(Viteなど)によって分割された設定ファイルがある場合、編集しているファイルがどの設定に紐付いているかを確認する必要があります。

以下のコマンドで、実際に適用されている最終的な設定を確認できます。

Shell
# 最終的な設定値を出力する
npx tsc --showConfig

この出力結果を確認することで、extends 等で上書きされた後の正確な値を把握できます。

まとめ

tsconfig.json は単なる設定ファイルではなく、プロジェクトの品質と開発速度を定義する設計図です。

モダンな開発においては、以下の3点が特に重要となります。

  • 厳格な型チェックstrict: true)による安全性の確保。
  • 最新のモジュールシステムへの追従module: NodeNext)によるエコシステムとの親和性。
  • 開発効率の最適化skipLibCheck, incremental)による高速なフィードバックループ。

TypeScriptの進化に伴い、新しいオプションや推奨される構成は日々変化しています。

一度設定して終わりにするのではなく、定期的に公式ドキュメントや最新のテンプレートをチェックし、プロジェクトの設定を最適化し続けることが、長期的な保守性を維持する鍵となります。

本記事で紹介した構成をベースに、皆さんのプロジェクトに最適な「最強のtsconfig」を構築してみてください。