TypeScript入門: `tsc –init`の使い方とtsconfig.json設定

TypeScript入門: tsc --initの使い方とtsconfig.json設定 の詳細な説明

TypeScriptは、JavaScriptに静的型付けやクラス、インターフェースといったオブジェクト指向的な概念を導入し、大規模なアプリケーション開発をより容易にするためのプログラミング言語です。TypeScriptで書かれたコードは、最終的にJavaScriptにコンパイル(変換)されて実行されます。

TypeScriptプロジェクトを始める上で避けて通れないのが、コンパイラの設定ファイルである tsconfig.json です。このファイルは、コンパイラ (tsc) がどのようにTypeScriptコードをコンパイルするか、どのファイルをコンパイル対象とするかなどを詳細に指定するために使用されます。

本記事では、TypeScriptのプロジェクト設定の第一歩として、tsc --init コマンドの使い方から始め、生成される tsconfig.json ファイルに含まれる様々な設定オプションについて、その意味と使い方を徹底的に解説します。約5000語にわたり、これらの設定がプロジェクト開発にどのように影響するのかを深く理解することを目指します。

はじめに: TypeScriptとコンパイル、そして設定ファイルの必要性

JavaScriptは動的なスクリプト言語であり、型のチェックは実行時まで行われません。これにより開発の自由度が高い反面、特に大規模なプロジェクトでは型の不一致による実行時エラーが頻繁に発生し、デバッグが困難になることがあります。

TypeScriptはこの問題を解決するために生まれました。TypeScriptコード(.ts または .tsx ファイル)には型情報が含まれており、コンパイル時にこれらの型チェックが行われます。これにより、多くのエラーを実行前に発見できるようになり、コードの信頼性が向上し、メンテナンスも容易になります。

TypeScriptコードをブラウザやNode.jsなどのJavaScript実行環境で動かすためには、TypeScriptコンパイラである tsc コマンドを使ってJavaScriptコード(.js ファイル)に変換するコンパイルという工程が必要です。

単一の小さなTypeScriptファイルであれば、コマンドラインから直接 tsc your_file.ts のように指定してコンパイルすることも可能です。しかし、実際のプロジェクトでは通常、複数のファイルから構成され、特定のディレクトリ構造を持っています。また、出力するJavaScriptのバージョン、使用するモジュールシステム、厳格な型チェックを行うか、出力先ディレクトリはどこにするかなど、コンパイルに関する様々な設定をプロジェクトごとに調整したいという要望が出てきます。

このようなプロジェクト全体にわたるコンパイル設定を一元管理するために使用されるのが tsconfig.json ファイルです。このファイルがあるディレクトリ、あるいはその上位ディレクトリで tsc コマンドを引数なしで実行すると、tsc は自動的に tsconfig.json を探し出し、その設定に基づいてプロジェクト全体のコンパイルを行います。

tsconfig.json は、TypeScriptプロジェクトの「設定マニュアル」のようなものです。これがないと、tsc は基本的な設定でコンパイルを行いますが、それでは多くのプロジェクトの要求を満たすことはできません。適切な tsconfig.json の設定は、開発効率、コードの品質、そしてビルドプロセスの管理において非常に重要です。

TypeScriptコンパイラ (tsc) の基本

tsc は TypeScript Compiler の略で、TypeScriptコードをJavaScriptコードに変換するためのコマンドラインツールです。

TypeScriptをインストールすると、npm install -g typescript または yarn global add typescript のようにグローバルインストールすることで、どこからでも tsc コマンドが使えるようになります。あるいは、プロジェクトのローカル依存として npm install --save-dev typescript のようにインストールし、npx tsc または yarn tsc として実行することも一般的です。後者のローカルインストールは、プロジェクトごとに異なるTypeScriptバージョンを使用できるため推奨されます。

tsc コマンドの基本的な使い方は以下の通りです。

  1. 単一ファイルのコンパイル:
    bash
    tsc your_file.ts

    これにより、your_file.ts と同じディレクトリに your_file.js が生成されます。

  2. 複数のファイルを指定してコンパイル:
    bash
    tsc file1.ts file2.ts file3.ts

    指定されたすべてのファイルが個別にコンパイルされます。

  3. 引数なしでプロジェクト全体をコンパイル:
    bash
    tsc

    現在のディレクトリ、または上位ディレクトリに tsconfig.json ファイルが存在する場合、tsc はその設定を読み込み、コンパイル対象と指定されたすべての .ts / .tsx ファイルをコンパイルします。これが、プロジェクト開発における一般的な使い方です。

tsconfig.json が存在しない状態で tsc を実行すると、デフォルト設定(ターゲットES5、CommonJSモジュール、厳格モードなしなど)でカレントディレクトリとそのサブディレクトリにあるすべての .ts ファイルをコンパイルしようとします。これは意図しない結果を招くことが多いため、通常は tsconfig.json を作成してから開発を始めます。

プロジェクト設定の必要性: なぜ tsconfig.json が不可欠なのか

先述の通り、小さなスクリプトであればファイル単体でコンパイルするだけで十分かもしれません。しかし、現実的なアプリケーションやライブラリは、通常、複数のファイルやディレクトリで構成されます。

例えば、以下のようなプロジェクト構造を考えます。

my-project/
├── src/
│ ├── components/
│ │ ├── Button.ts
│ │ └── Input.ts
│ ├── utils/
│ │ └── helper.ts
│ └── main.ts
├── tests/
│ └── main.test.ts
└── node_modules/
└── ...

このプロジェクトで main.ts をコンパイルしたい場合、main.ts はおそらく Button.tshelper.ts をインポートしているでしょう。TypeScriptコンパイラは、依存関係を解決しながらこれらのファイルを順序立ててコンパイルする必要があります。また、tests/ ディレクトリ以下のテストファイルは通常、本番コードとは別に管理し、コンパイル対象から除外したいと考えられます。さらに、node_modules/ ディレクトリ以下のライブラリもコンパイル対象に含める必要はありません(インストールされたライブラリは既にJavaScriptまたは型定義ファイルとして提供されているため)。

このようなシナリオに対応するためには、以下の点をコンパイラに伝える必要があります。

  • どのファイル/ディレクトリをコンパイル対象とするか: src/ ディレクトリ以下など。
  • どのファイル/ディレクトリをコンパイル対象から除外するか: node_modules/, tests/, ビルド出力先ディレクトリなど。
  • 出力するJavaScriptのバージョンは何か: 古いブラウザ向けか、最新のNode.js向けか。
  • 使用するモジュールシステムは何か: CommonJS (Node.js), ES Modules (モダンブラウザ/Node.js), AMD/UMD (レガシーブラウザ/バンドラ) など。
  • 厳格な型チェックをどこまで行うか: 可能な限りエラーを検出するか、あるいは既存のJavaScriptコードとの互換性を優先するか。
  • 出力先のディレクトリはどこか: ソースファイルと同じ場所に散らかすのではなく、一箇所にまとめたい。
  • ソースマップを生成するか: デバッグ時に元のTypeScriptコードを見たいか。
  • 型定義ファイル (.d.ts) を生成するか: 開発中のコードをライブラリとして公開する場合などに必要か。

これらの設定項目は多岐にわたり、プロジェクトの規模が大きくなるにつれてその重要性は増します。tsconfig.json は、これらの設定を全て記述し、チームメンバー間や異なる環境間でも一貫したビルドプロセスを保証するための中心的な役割を果たします。

tsc --init の使い方

新しいTypeScriptプロジェクトを開始する際、tsconfig.json を手動でゼロから作成するのは大変です。TypeScriptコンパイラは、このプロセスを簡単にするための便利なコマンドを提供しています。それが tsc --init です。

プロジェクトのルートディレクトリ(例えば my-project/ ディレクトリ)に移動し、以下のコマンドを実行します。

bash
cd my-project/
tsc --init

このコマンドを実行すると、特にエラーがなければ、カレントディレクトリに tsconfig.json という名前のファイルが新しく生成されます。

生成される tsconfig.json ファイルは、TypeScriptの公式が推奨する基本的な設定と、非常に詳細なコメントが含まれた状態になっています。コメントは各設定オプションの説明や、そのオプションがどのような状況で役立つかなどを解説しており、TypeScriptの設定について学ぶ上で非常に参考になります。

生成される tsconfig.json の内容は、TypeScriptのバージョンによって多少異なりますが、基本的な構造と主要なオプションは共通しています。以下に、生成されるファイルの典型的な構造の抜粋を示します。

``json
{
"compilerOptions": {
/* Language and Environment Options */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"module": "commonjs", /* Specify what module code is generated. */
// "rootDir": "./src", /* Specify the root folder within your source files. */
// "outDir": "./dist", /* Specify an output folder for all emitted files. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables
allowSyntheticDefaultImports` for type compatibility. /
“forceConsistentCasingInFileNames”: true, /
Ensure that casing is consistent in imported file paths. */

/* Type Checking Options */
"strict": true,                                      /* Enable all strict type-checking options. */
// "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */
"skipLibCheck": true                                 /* Skip type checking all .d.ts files. */

},
// “include”: [“src”], / Specify paths relative to baseUrl to include in the compilation. /
// “exclude”: [“node_modules”], / Specify an array of glob patterns that match files to be excluded from compilation. /
// “files”: [“core.ts”, “utils.ts”] / Specify an array of file names to include in the compilation. /
}
“`

この抜粋からもわかるように、tsc --init は様々なオプションをコメントアウトした状態で提供してくれます。これにより、どのようなオプションが存在するのかを一目で把握し、必要に応じてコメントアウトを解除して設定を有効化したり、値を変更したりすることで、プロジェクトに合った設定を効率的に構築できます。

tsc --init はあくまで「出発点」を提供するためのものです。プロジェクトの種類(Node.jsアプリケーション、ブラウザ向けフロントエンド、ライブラリなど)や開発スタイルによって、最適な設定は異なります。ここから、生成された tsconfig.json の内容を理解し、必要に応じてカスタマイズしていくことが重要です。

tsconfig.json の基本構造

tsconfig.json ファイルは、ルートにいくつかの主要なプロパティを持つJSONオブジェクトです。最も重要なのは compilerOptions プロパティですが、コンパイル対象ファイルを指定するためのプロパティも存在します。

主要なルートプロパティは以下の通りです。

  • compilerOptions: 必須かつ最も重要なプロパティです。 TypeScriptコンパイラの動作に関するあらゆる設定(出力JavaScriptのバージョン、モジュールシステム、型チェックの厳格さ、出力先ディレクトリなど)をここに記述します。
  • files: コンパイル対象とするファイルを個別にリストアップする場合に使用します。ファイルパスの配列を指定します。
  • include: コンパイル対象とするファイルを、ディレクトリ指定やワイルドカード(globパターン)を使って指定する場合に使用します。ファイルパスまたはglobパターンの配列を指定します。
  • exclude: include で指定されたファイルの中から、コンパイル対象から除外するファイルを指定する場合に使用します。globパターンの配列を指定します。
  • extends: 別の tsconfig.json ファイルの設定を継承する場合に使用します。設定を共通化したり、ベース設定の上にプロジェクト固有の設定を追加したりするのに便利です。
  • references: プロジェクト参照を指定する場合に使用します。主にモノレポ構成で、依存関係のある複数のTypeScriptプロジェクトを効率的に管理・ビルドするために使用します。

これらのプロパティのうち、compilerOptions がコンパイル方法自体を、files, include, exclude がコンパイル対象ファイルを、extends が設定の継承を、references がプロジェクト間の依存関係をそれぞれ制御します。

特に files, include, exclude は、コンパイル対象を特定するために相互に関連して動作します。この詳細は後述しますが、通常は includeexclude を組み合わせて使用することが一般的です。files は、ごく少数の特定のファイルを指定する場合にのみ使用されます。

もし files, include, exclude のいずれも指定されていない場合、tsctsconfig.json ファイルがあるディレクトリとそのサブディレクトリ内の全ての .ts, .tsx, .d.ts ファイルをコンパイル対象とします(ただし、node_modules ディレクトリや outDir で指定されたディレクトリはデフォルトで除外されます)。

compilerOptions の詳細

compilerOptions プロパティには、コンパイラの振る舞いを細かく制御するための膨大な数のオプションが含まれています。tsc --init で生成されるファイルには、主要なオプションがコメント付きでリストアップされています。ここでは、特に重要かつ頻繁に使用されるオプションについて、その意味と使い方を詳しく解説します。

target: 出力するJavaScriptのバージョン

このオプションは、生成されるJavaScriptコードのECMAScript(ES)バージョンを指定します。指定されたバージョンに応じて、TypeScriptの新しい構文(例: class, arrow function, let, const, async/await, for...of など)が、ターゲットのバージョンで利用可能な同等の機能に変換(トランスパイル)されます。

  • 指定可能な値: "es3", "es5", "es2015" (同 "es6"), "es2016", "es2017", "es2018", "es2019", "es2020", "es2021", "es2022", "esnext" (最新の安定版機能を含む)
  • tsc --init でのデフォルト: "es2016" など、比較的新しいバージョンが設定されていることが多いです。

どの target を選ぶべきか?

  • レガシー環境向け: IE11などをサポートする必要がある場合は "es5" を選択します。ただし、PromiseSymbol など、ES6以降の組み込みオブジェクトは、lib オプションで適切なライブラリを指定するか、ポリフィルを用意する必要があります。
  • モダンブラウザ向け: モダンなブラウザ(Chrome, Firefox, Edge, Safariの最新版など)をターゲットにする場合は、"es2017""es2018" など、比較的モダンなバージョンを選択することで、生成されるJavaScriptコードのサイズを小さくしたり、実行効率を向上させたりできます。async/await をそのまま利用したい場合は "es2017" 以降が必要です。
  • Node.js向け: 使用しているNode.jsのバージョンがサポートしている最新のESバージョンを選択するのが良いでしょう。Node.jsは比較的新しいES機能をすぐに取り込む傾向があります。
  • バンドラ利用時: WebpackやRollupなどのモダンなバンドラを利用している場合、TypeScriptによるトランスパイルは最小限(主に型除去)にとどめ、JavaScriptのトランスパイル(Babelなど)や最適化はバンドラに任せるという設計も可能です。この場合、"esnext""es2020" のような新しいバージョンを指定し、バンドラ側でターゲット環境に合わせたJSを生成させることがあります。

target を新しいバージョンに設定するほど、TypeScriptコンパイラが行うトランスパイルは少なくなり、生成されるコードは元のTypeScriptコードに近くなります。これは、コードの可読性を保ち、デバッグを容易にする効果もあります。

module: モジュールシステム

このオプションは、生成されるJavaScriptコードがどのモジュールシステムを使用するかを指定します。JavaScriptにはいくつかのモジュールシステムがあり、実行環境によってサポートされるものが異なります。

  • 指定可能な値: "none", "commonjs", "amd", "umd", "system", "es2015", "es2020", "es2022", "esnext", "node16", "nodenext"
  • tsc --init でのデフォルト: "commonjs" など、Node.js環境でよく使われるものが設定されていることが多いです。

どの module を選ぶべきか?

  • Node.jsアプリケーション: Node.jsは歴史的にCommonJSモジュールシステム (require/module.exports) を使用してきました。現在でも多くのnpmパッケージがCommonJS形式で提供されているため、"commonjs" を選択するのが一般的です。ただし、Node.js v12以降ではES Modules (import/export) も公式にサポートされており、package.json"type": "module" を指定するか、.mjs 拡張子を使用することでES Modulesを利用できます。Node.jsでES Modulesを使用する場合は "es2020""esnext", あるいは特定のバージョンに合わせた "node16", "nodenext" を選択します。
  • ブラウザ向けフロントエンド(バンドラ利用なし): モダンブラウザではES Modulesがネイティブにサポートされています。バンドラを使用しない場合は "es2015" 以降、あるいは "esnext" を選択することで、ブラウザが直接解釈できる import/export 構文で出力できます。
  • ブラウザ向けフロントエンド(バンドラ利用あり): Webpack, Rollup, Parcelなどのバンドラは、様々なモジュールシステムを入力として受け取り、最終的にブラウザ向けのJavaScript(通常はES ModulesまたはIIFE(即時関数)形式)にまとめることができます。この場合、TypeScriptコンパイラは型チェックと最小限の変換だけを行い、モジュールの解決やバンドリングはバンドラに任せることが一般的です。バンドラはES Modules形式の入力を最も効率的に処理できるため、TypeScriptの module オプションには "esnext" または "es2020" など、バンドラが理解しやすいES Modules形式を指定することが推奨されます。 これは、バンドラにモジュールグラフ構築の情報を正確に伝えるためです。
  • レガシーブラウザ向け(バンドラ利用なし): AMD (RequireJSなど) や UMD (CommonJS/AMD/グローバルをサポート) は、ES Modulesが普及する前にブラウザでモジュール管理を行うために使用されました。これらの環境をターゲットにする場合は、それぞれ "amd" または "umd" を選択します。
  • ライブラリ開発: 開発するライブラリがNode.jsとブラウザの両方で使用される可能性がある場合、UMD形式 ("umd") で出力するのが一つの選択肢です。ただし、最近ではES Modules ("esnext") とCommonJS ("commonjs") の両方を、Rollupなどのバンドラを使って出力するアプローチが主流になっています。

target オプションと module オプションは密接に関連しています。例えば、target: "es5" としながら module: "esnext" と設定すると、ES5でサポートされていない import/export 構文が出力されるため、これは通常意図した動作ではありません。TypeScriptコンパイラは、これらの組み合わせについて適切な警告を出したり、互換性のあるデフォルト値を適用したりします。

lib: 使用する標準ライブラリ

このオプションは、TypeScriptの型チェックを行う際に参照する標準ライブラリの型定義ファイル (.d.ts) のセットを指定します。JavaScriptの実行環境(ブラウザ、Node.jsなど)にはそれぞれ異なる組み込みオブジェクトやAPIが存在します。lib オプションを使用することで、開発している環境に応じた正確な型情報をTypeScriptコンパイラに提供できます。

  • 指定可能な値: ["dom", "es5", "es2015", "es2016", ... , "esnext", "dom.iterable", "webworker", "scripthost", "deno.ns", "deno.window"] など、多数のオプションがあります。
  • tsc --init でのデフォルト: target オプションの値に基づいて、適切なデフォルトセットが自動的に選択されます。例えば target: "es5" の場合は ["dom", "es5", "scripthost"] のような組み合わせが、target: "es2016" の場合は ["dom", "es2016", "dom.iterable", "scripthost"] のような組み合わせがデフォルトで有効になります。

lib オプションの重要性

JavaScriptの標準機能(Array, String, Promise, Map, Set など)や、ブラウザ固有のAPI(document, window, setTimeout など)、Node.js固有のAPI(process, Buffer, require など)は、それぞれの環境で提供されるグローバルオブジェクトや関数です。これらの型情報がなければ、TypeScriptはそれらを any 型と推論するか、存在しないものとして扱ってエラーとします。

例えば、ブラウザ環境で document.getElementById('my-element') のようなコードを書く場合、lib オプションに "dom" が含まれていなければ、document が何であるか、どのようなメソッドを持つかを知ることができません。

  • ブラウザ環境: "dom", "dom.iterable" を含めるのが一般的です。
  • Node.js環境: "esnext" のような最新のES機能に加えて、@types/node などのNode.js固有の型定義ライブラリをインストールして使用します。lib 自体にはNode.js固有のものは含まれません。
  • 特定のES機能: target オプションで指定したバージョンに含まれるES機能の型はデフォルトで含まれますが、例えば target: "es5"Promise を使用したい場合は、lib"es2015" を追加する必要があります ("es2015" ライブラリには Promise の型定義が含まれるため)。

lib オプションは 배열で複数の値を指定できます。例えば ["dom", "es2015", "es2016", "es2017"] のように指定することで、複数のバージョンの標準ライブラリや環境固有のライブラリの型定義を組み合わせることができます。デフォルトで自動的に含まれるライブラリに加えて、特定の機能や環境の型定義を明示的に追加したい場合に lib オプションを使用します。

strict: 厳格モード関連のフラグを一括有効化

"strict": true を設定すると、TypeScriptコンパイラの厳格な型チェックに関連する複数のオプションがまとめて有効になります。これらのオプションは、潜在的なバグの原因となる可能性のあるコードパターンを検出するために役立ちます。可能な限り、"strict": true を有効にして開発することが強く推奨されます。

"strict": true が有効にする主なオプションは以下の通りです。

  1. noImplicitAny: 暗黙的な any 型の使用を禁止します。型注釈がない変数宣言で初期値がない場合や、関数の引数で型が推論できない場合などに any 型が推論されるのを防ぎ、明示的な型付けを強制します。
    “`typescript
    // strict: true または noImplicitAny: true の場合エラー
    function processData(data) { // ‘data’ は暗黙的な any
    console.log(data);
    }

    // OK: 明示的に型付け
    function processData(data: any) {
    console.log(data);
    }
    // OK: 明示的に型付け (より良い)
    function processData(data: string) {
    console.log(data);
    }
    ``any型はTypeScriptの型チェックを無効にするため、意図しないany` 型の使用はバグの原因となります。このオプションは、より厳密で安全なコードを書くために非常に重要です。

  2. strictNullChecks: null および undefined に関する厳格なチェックを有効にします。デフォルトでは、ほとんどの型は null および undefined を許容しますが、このオプションを有効にすると、明示的に null または undefined を許容する型(例: string | null, number | undefined)でない限り、それらの値を代入したり使用したりするとエラーになります。
    “`typescript
    let s: string = “hello”;
    // strictNullChecks: true の場合エラー
    s = null;
    s = undefined;

    let n: number | null = 123; // null を許容する型
    n = null; // OK
    ``
    このオプションは、ランタイムでの "cannot read property of undefined" のようなエラーを大幅に削減するのに役立ちます。Optional Chaining (
    ?.) や Nullish Coalescing (??`) 演算子と組み合わせて使用することで、安全かつ簡潔にnull/undefinedを扱うコードを書くことができます。

  3. strictFunctionTypes: 関数の引数の型に関する双変性チェックを厳格に行います。これは少し高度な概念ですが、コールバック関数などで型の安全性を高めます。
    “`typescript
    type Predicate = (x: number) => boolean;
    type Comparer = (x: number, y: number) => number;

    const p: Predicate = (x: number | string) => true; // strictFunctionTypes: true の場合エラー
    // 関数型においては、引数の型はより広い型に代入できません。
    // なぜなら、Predicate の関数は number 型を受け取ることを期待していますが、
    // string 型の引数が渡された場合に適切に処理できない可能性があるためです。
    “`

  4. strictBindCallApply: 関数メソッド (bind, call, apply) の使用時に、ターゲット関数のシグネチャに対して引数が正しく渡されているかを厳格にチェックします。
    “`typescript
    function greet(this: any, name: string) {
    console.log(“Hello, ” + name);
    }

    // strictBindCallApply: true の場合エラー (引数の数が違う)
    greet.call(null, “Alice”, 123);
    “`

  5. strictPropertyInitialization: クラスのプロパティがコンストラクタで初期化されることを保証します。コンストラクタ内で初期化されないインスタンスプロパティは、プロパティ宣言時に明示的な初期化子を持つか、または definite assignment assertion (!) を使用する必要があります。
    “`typescript
    class MyClass {
    name: string; // strictPropertyInitialization: true の場合エラー
    age: number = 0; // OK: 初期化子がある
    id!: string; // OK: definite assignment assertion を使用

    constructor(name: string) {
    this.name = name; // OK: コンストラクタで初期化
    // this.id はコンストラクタで初期化されていないが、! が付いているためエラーにならない (開発者の責任)
    }
    }
    “`

  6. noImplicitThis: 暗黙的に any 型と推論される this の使用を禁止します。通常、クラスメソッド内で this の型は明確ですが、グローバル関数やコールバック関数などで this を使用する際に問題となることがあります。関数の最初の引数に明示的な this 型注釈を追加することで回避できます。
    “`typescript
    // strict: true または noImplicitThis: true の場合エラー (this は暗黙的な any)
    function sayHello(this: any) {
    console.log(“Hello from ” + this);
    }

    // OK: this の型を明示的に指定
    function sayHello(this: Window) {
    console.log(“Hello from ” + this.location.href);
    }
    “`

  7. useUnknownInCatchVariables: catch 節の変数に unknown 型を使用することを強制します。以前はデフォルトで any 型が使用されていましたが、unknown 型の方がより安全です。unknown 型の変数を使用する前に、その型を絞り込む(typeof や instanceof などでチェックする)必要があるため、エラーハンドリングがより堅牢になります。
    “`typescript
    try {
    // …
    } catch (e) {
    // strict: true または useUnknownInCatchVariables: true の場合、e は unknown 型
    // console.error(e.message); // unknown 型には .message プロパティがあるか不明なのでエラー

    if (e instanceof Error) {
    console.error(e.message); // OK: e が Error 型であることが確認できた
    } else {
    console.error(“An unknown error occurred:”, e);
    }
    }
    “`

"strict": true はこれらのチェックを全て有効にしますが、プロジェクトの状況によっては、特定の厳格チェックを一時的に無効にしたい場合があります。その場合は、"strict": true を維持しつつ、個別のフラグ(例: "noImplicitAny": false)を明示的に指定してオーバーライドすることができます。ただし、長期的なコード品質を考慮すると、できる限りこれらの厳格チェックを有効にしておくことが推奨されます。

esModuleInterop: CommonJS/AMDモジュールとESモジュールの互換性

JavaScriptのエコシステムでは、CommonJS (require/module.exports) と ES Modules (import/export) という主に2つのモジュールシステムが広く使われています。TypeScriptはどちらのシステムでもコードを書くことができますが、異なるモジュールシステム間で互換性の問題が発生することがあります。特に、CommonJSモジュールをES Modules形式でインポートしようとした場合に問題が起こりやすいです。

例えば、CommonJSモジュールである lodashimport _ from 'lodash'; のようにES Modules形式でデフォルトインポートしようとすると、通常は _ に期待通りの値が入りません。CommonJSの module.exports = ... はES Modulesのデフォルトエクスポートとは異なる仕組みだからです。

"esModuleInterop": true を設定すると、TypeScriptコンパイラは生成するJavaScriptコードにヘルパー関数を追加し、CommonJS/AMDモジュールからのインポートがES Modulesの import 構文でより自然に扱えるようにします。具体的には、以下の2つのオプションが同時に有効になります。

  • allowSyntheticDefaultImports: デフォルトエクスポートを持たないモジュール(CommonJSなど)に対して、あたかもデフォルトエクスポートを持っているかのようにインポート構文 (import Foo from "foo") を使用できるようにします。これは型チェックのためだけで、実際のランタイムの動作を変更するものではありません。
  • __esModuleInterop: 生成されるJavaScriptコードに、CommonJSの exports オブジェクトがES Modulesのデフォルトエクスポートとして扱えるようにするためのランタイムヘルパーコードを追加します。

なぜ "esModuleInterop": true が推奨されるのか?

多くのnpmパッケージはCommonJS形式で公開されています。フロントエンド開発でWebpackなどのバンドラを使用する場合でも、Node.js開発の場合でも、CommonJS形式のライブラリをES Modules形式のコードからインポートすることはよくあります。"esModuleInterop": true は、この異なるモジュールシステム間の互換性問題を吸収し、より直感的で一貫した import 構文で外部ライブラリを扱えるようにするため、現在のTypeScriptプロジェクトではほぼ必須の設定となっています。

tsc --init で生成される tsconfig.json でも、通常このオプションがデフォルトで有効化(コメントアウトされていない状態)になっています。特に理由がない限り、このオプションは常に有効にしておくべきです。

forceConsistentCasingInFileNames: ファイル名の大文字小文字を区別

このオプションを有効にすると、TypeScriptコンパイラはソースファイルやモジュールのインポートパスにおいて、ファイル名の大文字小文字の区別を厳格にチェックします。

多くのオペレーティングシステム(Windows, macOSのデフォルト設定など)では、ファイルシステムは大文字小文字を区別しません(ケースインセンシティブ)が、Linuxなどのシステムでは大文字小文字を区別します(ケースセンシティブ)。

例えば、Windows環境で import { foo } from './MyModule'; と書いても、実際のファイル名が mymodule.ts であれば問題なく動作することがあります。しかし、このコードをLinux環境にデプロイすると、ファイル名の大文字小文字が一致しないためにモジュールが見つからず、エラーになる可能性があります。

"forceConsistentCasingInFileNames": true を有効にすることで、開発中にこのような潜在的な問題を早期に発見できます。特にクロスプラットフォームでの開発や、チーム開発で異なるOSを使用している場合に非常に重要な設定です。

tsc --init で生成される tsconfig.json でも、通常このオプションがデフォルトで有効化されています。常に有効にしておくべき推奨設定です。

skipLibCheck: 宣言ファイルの型チェックをスキップ

このオプションを有効にすると、node_modules ディレクトリ以下に存在する型宣言ファイル (.d.ts ファイル) の型チェックをスキップします。

大規模なプロジェクトや、多数のライブラリを使用しているプロジェクトでは、依存ライブラリの型宣言ファイルの量が膨大になることがあります。これらのファイルの型チェックは、TypeScriptコンパイラにとって無視できない負担となり、コンパイル時間が長くなる原因となることがあります。

"skipLibCheck": true は、開発中の自身のコードの型チェックのみに集中することで、コンパイル時間を短縮する効果があります。ただし、このオプションを有効にすると、依存ライブラリの型定義ファイル自体に型エラーが含まれていても報告されなくなります。一般的に、広く使われているライブラリの型定義ファイルは十分にテストされているため、このオプションを有効にしても問題となることは少ないです。

コンパイル時間を改善したい場合に検討するオプションですが、依存ライブラリの型定義に疑いがある場合や、@types/ パッケージを自分で作成・修正している場合は、一時的に無効にする必要があるかもしれません。

outDir: 出力ディレクトリ

このオプションは、コンパイルによって生成されたJavaScriptファイルやソースマップ、宣言ファイルなどを出力するディレクトリを指定します。

  • 指定可能な値: ディレクトリパス (例: "./dist", "../build")
  • デフォルト: 指定しない場合、生成されたファイルは対応する .ts ファイルと同じディレクトリに出力されます。

例えば "outDir": "./dist" と設定すると、src/main.tsdist/main.js として、src/utils/helper.tsdist/utils/helper.js として出力されます。プロジェクトのソースコードと生成されたコードを分離するために非常に便利なオプションです。

通常、ビルド生成物は distbuild という名前のディレクトリにまとめられます。このディレクトリはバージョン管理システム(Gitなど)の管理対象から除外(.gitignore に追加)するのが一般的です。

rootDir: ソースファイルのルートディレクトリ

このオプションは、コンパイル対象となるソースファイルのルートディレクトリを指定します。outDir オプションと組み合わせて使用することで、出力ディレクトリ内でのファイル構造を制御できます。

  • 指定可能な値: ディレクトリパス (例: "./src")
  • デフォルト: files, include, exclude オプションに基づいて、TypeScriptコンパイラが共通のルートディレクトリを自動的に決定します。

例えば、ソースファイルが全て src/ ディレクトリ以下にあり、"rootDir": "./src""outDir": "./dist" と設定した場合、src/components/Button.tsdist/components/Button.js として出力されます。rootDir を適切に設定することで、ソースディレクトリの構造を保ったまま、出力ディレクトリにファイルが生成されます。

もし rootDir を指定せず、src/tests/ の両方にソースファイルがある場合、コンパイラはこれらの共通のルートディレクトリ(この例ではプロジェクトルート ./)を rootDir とみなします。その結果、src/main.tsdist/src/main.js として、tests/main.test.tsdist/tests/main.test.js として出力されるかもしれません。これは意図しないファイル構造になる可能性があります。このような場合は rootDir を明示的に指定することで、出力構造を制御できます。

declaration (.d.ts ファイル生成)

このオプションを有効にすると、TypeScriptコンパイラは対応するJavaScriptファイル (.js) と共に、型宣言ファイル (.d.ts ファイル) を生成します。

  • 指定可能な値: true または false
  • デフォルト: false

型宣言ファイルは、JavaScriptコードの型情報のみを記述したファイルであり、実際の実行コードは含まれません。主に、開発したライブラリをTypeScriptやJavaScript(JSDocなどで型情報を活用する場合)から利用する際に、そのライブラリがどのような関数、クラス、変数などを公開しており、それらがどのような型を持つかを伝えるために使用されます。

公開するnpmパッケージを作成する場合、declaration: true はほぼ必須の設定です。これにより、そのパッケージをTypeScriptプロジェクトにインストールした際に、型チェックやコード補完が適切に機能するようになります。

declarationDir オプションを使用して、.d.ts ファイルの出力先ディレクトリを outDir とは別に指定することも可能です。

sourceMap: ソースマップの生成

このオプションを有効にすると、コンパイルによって生成されたJavaScriptファイルに対応するソースマップファイル (.js.map ファイル) が生成されます。

  • 指定可能な値: true または false
  • デフォルト: false

ソースマップは、生成されたJavaScriptコードの各行が、元のTypeScriptコードのどの部分に対応するかを記録したファイルです。ソースマップを使用すると、ブラウザの開発者ツールやNode.jsのデバッガで、生成されたJavaScriptコードではなく、元のTypeScriptコードに対してブレークポイントを設定したり、変数の値を検査したりすることができるようになります。

デバッグの効率が大幅に向上するため、開発環境やステージング環境向けのビルドでは sourceMap: true を設定することが強く推奨されます。本番環境向けでは、ソースマップを公開するかどうかはセキュリティやデバッグの必要性によって判断します。

removeComments: コメントの削除

このオプションを有効にすると、コンパイル時にTypeScriptソースコード中のコメントが削除されます。

  • 指定可能な値: true または false
  • デフォルト: false

生成されるJavaScriptファイルのサイズをわずかに削減する効果がありますが、デバッグ時などに元のコメントが見えなくなってしまうため、通常は false のままにするか、sourceMap オプションと組み合わせて使用します(ソースマップがあれば、元のTSコードのコメントを参照できます)。

noEmitOnError: エラー発生時のJS出力停止

このオプションを有効にすると、TypeScriptコンパイラが型エラーなどのコンパイルエラーを検出した場合、JavaScriptファイルの生成を停止します。

  • 指定可能な値: true または false
  • デフォルト: false (TypeScript 2.0以降の新しいプロジェクトテンプレートでは true が推奨されることが多い)

noEmitOnError: true は、エラーを含む不正なJavaScriptファイルが生成されてしまうことを防ぎます。これは、特に自動ビルドやCI/CDパイプラインにおいて非常に重要です。コンパイルエラーが発生した時点でビルドプロセス全体を失敗させることで、不正なコードがデプロイされるのを防ぐことができます。

このオプションは、開発初期段階で頻繁にエラーが発生する場合は無効にしておくと便利ですが、プロジェクトがある程度固まったら有効にすることが強く推奨されます。

incremental: インクリメンタルビルド

このオプションを有効にすると、TypeScriptコンパイラは前回のコンパイル情報をキャッシュし、変更されたファイルとその依存関係のみを再コンパイルすることで、次回のコンパイル時間を大幅に短縮します。

  • 指定可能な値: true または false
  • デフォルト: false

"incremental": true を設定すると、コンパイルの出力ディレクトリ(outDir など)に .tsbuildinfo というファイルが生成されます。このファイルにインクリメンタルビルドに必要な情報が格納されます。

特に大規模なプロジェクトでは、クリーンビルド(全てのファイルを最初からコンパイル)に時間がかかりますが、インクリメンタルビルドを有効にすることで、ファイル変更時の再コンパイルを非常に高速化できます。開発時の --watch モードや、references を使用したマルチプロジェクト構成でのビルド(tsc -b)と組み合わせて使用すると絶大な効果を発揮します。

このオプションは、ビルド速度がボトルネックになっている場合に非常に有効です。ただし、ディスク容量をわずかに消費します。

paths, baseUrl: モジュール解決のエイリアス設定

これらのオプションは、モジュールのインポートパスの解決方法をカスタマイズするために使用します。主に、相対パスのネストが深くなるのを避けたり、特定のディレクトリをモジュールパスのルートとして扱ったりするために使用されます。

  • baseUrl: モジュールパスの解決基準となるベースディレクトリを指定します。例えば "baseUrl": "./src" と設定すると、import { helper } from 'utils/helper'; のような絶対パス形式のインポートは、./src/utils/helper を参照しようとします。
  • paths: baseUrl を基準として、特定のモジュールパスを別のパスにマッピングするエイリアスを設定します。例えば "paths": { "@/*": ["./*"] } と設定すると、import { Button } from '@/components/Button'; というインポートは、baseUrl (例: ./src) を基準とした ./components/Button を参照するようになります。これは、import { Button } from '../components/Button'; のように階層が深くなった相対パスを @/ という短いエイリアスに置き換えるのに便利です。

これらのオプションは、大規模なプロジェクトや、複雑なディレクトリ構造を持つプロジェクトで、インポート文を簡潔に保ち、コードの可読性を向上させるために役立ちます。バンドラ(Webpackなど)やテストランナー(Jestなど)でも同様のパスエイリアス設定が必要になることが多いため、tsconfig.json の設定と整合性を保つ必要があります。

jsx: JSXの扱い方

ReactやPreactなどのライブラリでJSX構文(.tsx ファイル)を使用する場合、このオプションで生成されるJavaScriptコードの形式を指定します。

  • 指定可能な値: "preserve", "react", "react-native", "react-jsx", "react-jsxdev"
  • tsc --init でのデフォルト: JSXが有効になる tsconfig.json テンプレートの場合、"react" などが設定されていることが多いです。

  • "preserve": JSX構文をそのまま出力します。これは、JavaScriptへの変換(例えばBabelなど)を別のツールに任せる場合に選択します。

  • "react": React.createElement() を使用する形式に変換します。React v17より前のバージョンや、React v17以降でもレガシーなJSX変換を使用する場合に選択します。
  • "react-native": React Native向けの変換を行います。
  • "react-jsx": 新しいJSX変換 (react/jsx-runtime を使用) を行います。React v17以降で推奨される設定です。
  • "react-jsxdev": "react-jsx" と同様ですが、開発用の追加情報を含みます。

どの設定を選択するかは、使用しているライブラリ(React, Preactなど)のバージョンや、ビルドパイプライン全体でJSX変換をどのツールが担当するかによって決まります。

その他の重要な compilerOptions

compilerOptions には他にも多数のオプションがあります。生成された tsconfig.json ファイルのコメントには、それぞれの簡単な説明が記載されています。いくつかよく使われるものを簡単に紹介します。

  • allowJs: TypeScriptプロジェクト内でJavaScriptファイル (.js) をコンパイル対象に含めることを許可します。既存のJavaScriptコードを段階的にTypeScriptに移行する際に便利です。
  • checkJs: allowJs: true と組み合わせて使用し、JavaScriptファイルに対してもJSDocコメントに基づいた基本的な型チェックを行います。
  • maxNodeModuleJsDepth: checkJs を使用している場合に、node_modules ディレクトリを再帰的に辿って型チェックを行う深さを制限します。大規模な node_modules のチェックによる性能劣化を防ぎます。
  • resolveJsonModule: .json ファイルをモジュールとしてインポートすることを許可します。
  • allowSyntheticDefaultImports: "esModuleInterop": true が有効にするオプションの一つですが、単独でも使用できます。デフォルトエクスポートを持たないモジュールに対するデフォルトインポート構文を型チェックレベルで許可します。
  • isolatedModules: 各ファイルを独立したモジュールとしてコンパイルできることを保証するチェックを有効にします。これにより、Babelなどのツールで個別にトランスパイルする際に発生しうる問題を検出できます。
  • noEmit: コンパイルは行いますが、JavaScriptファイルなどを一切出力しないようにします。型チェックだけを行いたい場合(例えばリンターの一部として)に便利です。
  • noUnusedLocals: 使用されていないローカル変数やパラメータに対してエラーを報告します。デッドコードの検出に役立ちます。
  • noUnusedParameters: 使用されていない関数パラメータに対してエラーを報告します。
  • experimentalDecorators: デコレータ構文を有効にします(まだ標準化段階にある機能のため)。Angularなどで使用されます。
  • emitDecoratorMetadata: デコレータに関するメタデータを生成します(主にAngularで使用)。experimentalDecorators とセットで使用されることが多いです。

これらのオプションは、プロジェクトの要件や使用するフレームワーク/ライブラリによって適切に設定する必要があります。tsc --init で生成されたコメントをよく読み、公式ドキュメントも参照しながら設定をカスタマイズしていくことをお勧めします。

files, include, exclude: コンパイル対象ファイルの指定

tsconfig.json のルートレベルにある files, include, exclude プロパティは、TypeScriptコンパイラがどのファイルをコンパイル対象とするかを制御するために使用されます。

  • files: コンパイル対象としたいファイルを個別にリストアップします。パスの配列で指定します。
    json
    "files": [
    "src/core.ts",
    "src/utils/helper.ts",
    "types/global.d.ts" // 型定義ファイルも指定可能
    ]

    この方法は、コンパイル対象ファイルが非常に少ない場合や、特定のファイルだけをコンパイルしたい場合に適しています。しかし、ファイル数が多いプロジェクトでは管理が煩雑になるため、あまり一般的ではありません。

  • include: コンパイル対象としたいファイルやディレクトリを、ワイルドカードパターン(globパターン)を使って指定します。パスまたはglobパターンの配列で指定します。
    json
    "include": [
    "src/**/*.ts", // srcディレクトリ以下の全ての.tsファイルを対象
    "src/**/*.tsx" // srcディレクトリ以下の全ての.tsxファイルを対象
    ]

    Globパターンでは以下の記号がよく使われます。

    • *: 0文字以上の任意の一致(/. は含まない)
    • **: 0個以上のディレクトリを含む任意の一致(再帰的な探索)
    • ?: 任意の1文字

    例:
    * *.ts: カレントディレクトリの全ての .ts ファイル
    * src/*.ts: src ディレクトリの全ての .ts ファイル
    * src/**/*.ts: src ディレクトリとその全てのサブディレクトリの全ての .ts ファイル
    * **/*.ts: カレントディレクトリとその全てのサブディレクトリの全ての .ts ファイル

    include は、特定のディレクトリ以下(例: src/)や、特定の拡張子のファイル(例: .ts, .tsx)をまとめて指定するのに非常に便利です。

  • exclude: include で指定されたファイルの中から、コンパイル対象から除外したいファイルを、globパターンを使って指定します。globパターンの配列で指定します。
    json
    "exclude": [
    "node_modules", // node_modules ディレクトリを除外 (デフォルトでも除外されることが多い)
    "dist", // ビルド出力先ディレクトリを除外
    "**/*.test.ts" // 拡張子が .test.ts のファイルを除外
    ]

    exclude は、テストファイル、ビルド出力先ディレクトリ、各種設定ファイル、不要なサンプルコードなどをコンパイル対象から外すために使用します。node_modules ディレクトリはデフォルトで除外されますが、明示的に指定しておくと意図が明確になります。

これらのプロパティの相互作用と優先順位

  1. files が指定されている場合、コンパイル対象は files にリストアップされたファイルのみになります。includeexclude は無視されます。
  2. files が指定されていない場合、コンパイル対象は include で指定されたファイルの中から、exclude で除外されたファイルを除いたものになります。
  3. files, include, exclude のいずれも指定されていない場合、tsconfig.json があるディレクトリとそのサブディレクトリ以下の全ての .ts, .tsx, .d.ts ファイルが対象となります。ただし、以下のディレクトリはデフォルトで常に除外されます。
    • node_modules
    • compilerOptions.outDir で指定されたディレクトリ
    • compilerOptions.declarationDir で指定されたディレクトリ
    • compilerOptions.rootDir が指定されており、その外にあるファイル

一般的なプロジェクト構成では、files は使用せず、include でソースコードディレクトリ(例: "src""**/*")を指定し、exclude で不要なディレクトリやファイルを指定するパターンが最もよく使われます。

tsc --init で生成される tsconfig.json では、files, include, exclude はいずれもコメントアウトされています。つまり、デフォルトのルール(node_modules などを除く全て)が適用される初期状態になっています。通常は、プロジェクト構造に合わせて includeexclude を適切に設定する必要があります。

extends: 設定の継承

extends プロパティを使用すると、別の tsconfig.json ファイルの設定を継承することができます。

  • 指定可能な値: 継承元となる tsconfig.json ファイルへのパス(相対パスまたはnpmパッケージ名)
    json
    {
    "extends": "./tsconfig.base.json",
    "compilerOptions": {
    "outDir": "./dist/app"
    }
    }

extends の使い方とメリット

  1. 設定の共通化: 複数のプロジェクトやモジュールで共通の設定を使用したい場合に便利です。例えば、モノレポ構成で、全てのパッケージに適用したい基本的な設定を一つの tsconfig.base.json ファイルに記述し、各パッケージの tsconfig.json でそれを extends します。
  2. 設定の上書き: 継承元の設定をベースとして、継承先のファイルで特定のオプションを上書きしたり、新しいオプションを追加したりできます。上記の例では、tsconfig.base.json の全てのオプションを継承しつつ、outDir だけを ./dist/app に上書きしています。
  3. フレームワーク/ライブラリの提供する設定: 例えば、ReactやAngularのプロジェクトでは、それぞれの環境に最適化された tsconfig.json 設定がnpmパッケージとして提供されていることがあります。それを extends することで、自分で細かい設定をする手間を省けます。
    json
    {
    "extends": "@angular/compiler-cli/tsconfig.json",
    "compilerOptions": {
    // プロジェクト固有の設定や上書き
    }
    }

継承された設定は、継承先のファイルの同じプロパティによって上書きされます。配列オプション(lib, include, exclude など)も上書きとなり、継承元と継承先の値が結合されるわけではない点に注意が必要です。

extends を使うことで、設定の重複を避け、管理を容易にすることができます。特に大規模なプロジェクトや、複数のTypeScriptプロジェクトが存在する場合に非常に有効です。

references: プロジェクト参照

references プロパティは、主にモノレポ構成で、互いに依存関係を持つ複数のTypeScriptプロジェクトを管理するための高度な機能です。

  • 指定可能な値: 参照するプロジェクトの tsconfig.json ファイルへのパスの配列
    json
    {
    "compilerOptions": {
    // ... (composite: true が必要)
    },
    "references": [
    { "path": "../core" },
    { "path": "../utils" }
    ]
    }

references の使い方とメリット

例えば、my-monorepo/ の中に packages/core, packages/utils, packages/app という3つのTypeScriptプロジェクトがあり、appcoreutils に依存しているとします。各プロジェクトはそれぞれのディレクトリに tsconfig.json を持っています。

この場合、packages/app/tsconfig.jsonreferences../core../utils を指定します。

references を設定すると、以下のメリットが得られます。

  1. 依存関係の自動解決: tsc コマンドに -b (build) フラグを付けて実行する (tsc -b) と、TypeScriptコンパイラは references を見てプロジェクト間の依存関係を理解します。そして、依存元のプロジェクト(core, utils)を先にビルドし、その後に依存先のプロジェクト(app)をビルドするという、適切な順序でビルドを実行します。
  2. ビルドの高速化: tsc -b はインクリメンタルビルドに対応しています。変更されたプロジェクトとその依存先のプロジェクトのみが再ビルドされるため、大規模なモノレポ全体を毎回クリーンビルドするよりもはるかに高速にビルドが完了します。
  3. 型チェックの改善: 依存関係のあるプロジェクト間での型チェックがより正確に行われるようになります。
  4. 開発環境の改善: エディタ(VS Codeなど)がプロジェクト参照を理解することで、プロジェクト間の移動、依存元のコード変更による依存先での型エラーの即時検出などがスムーズに行えるようになります。

references を使用するには、参照される側のプロジェクトの tsconfig.jsoncompilerOptions.composite: true を設定する必要があります。composite: true を設定すると、自動的に declaration: true も有効になります(無効にすることも可能ですが、参照元プロジェクトの型情報が必要になるため、通常は有効にしておきます)。

モノレポ構成を採用している場合、references はビルド効率と開発体験を劇的に改善するための非常に重要な機能です。

実践的な tsconfig.json の例

プロジェクトの種類によって、推奨される tsconfig.json の設定は異なります。ここでは、いくつかの典型的なシナリオにおける設定例を示します。

1. Node.js アプリケーション向け

Node.js 環境で実行されるバックエンドアプリケーションやCLIツールなどの設定です。

json
{
"compilerOptions": {
"target": "es2020", /* Node.jsの比較的新しいバージョンをターゲット */
"module": "commonjs", /* Node.jsで一般的なCommonJSモジュール */
"lib": ["es2020"], /* Node.js標準ライブラリの型は @types/node で提供 */
"strict": true, /* 厳格な型チェックを有効に */
"esModuleInterop": true, /* CommonJSモジュールとの互換性 */
"forceConsistentCasingInFileNames": true, /* ファイル名の大文字小文字を区別 */
"outDir": "./dist", /* 出力ディレクトリ */
"rootDir": "./src", /* ソースディレクトリ */
"skipLibCheck": true, /* 依存ライブラリの型チェックをスキップ */
"noEmitOnError": true, /* エラー発生時はJSを出力しない */
"incremental": true /* インクリメンタルビルドを有効に */
},
"include": [
"src/**/*.ts" /* srcディレクトリ以下の全ての.tsファイルを対象 */
],
"exclude": [
"node_modules", /* node_modulesを除外 (デフォルトでも除外) */
"dist" /* 出力ディレクトリを除外 */
]
}

解説:
* target は使用するNode.jsのバージョンに合わせて調整します。最新のLTSなら es2020es2021 などで十分でしょう。
* modulecommonjs が一般的ですが、ES Modulesを使用する場合は es2020node16/nodenext に変更します。
* lib にはESの標準機能のみを指定し、Node.js固有の型情報は npm install --save-dev @types/node でインストールします。
* strict は必須レベルです。
* outDir./dist などの出力先を指定します。
* include でソースファイルのあるディレクトリを指定し、exclude で不要なディレクトリを除外します。

2. ブラウザ向けフロントエンド(モダンバンドラ利用)

Webpack, Rollup, Parcel などのモダンなバンドラを使用するReact, Vue, Angularなどのフロントエンドプロジェクト向けの設定です。

json
{
"compilerOptions": {
"target": "es2020", /* バンドラでトランスパイルすることを前提に新しいターゲット */
"module": "esnext", /* バンドラが理解しやすいES Modules形式 */
"lib": ["dom", "dom.iterable", "esnext"], /* DOM APIと最新のES機能の型 */
"strict": true, /* 厳格な型チェックを有効に */
"esModuleInterop": true, /* モジュール互換性 */
"forceConsistentCasingInFileNames": true, /* ファイル名の大文字小文字を区別 */
"jsx": "react-jsx", /* または "react", "preserve", "react-native" など */
"sourceMap": true, /* デバッグ用にソースマップを生成 */
"outDir": "./dist", /* 出力ディレクトリ (通常バンドラが出力するが、型定義用などに設定) */
"rootDir": "./src", /* ソースディレクトリ */
"skipLibCheck": true, /* 依存ライブラリの型チェックをスキップ */
"noEmit": true, /* バンドラにJS生成を任せる場合は true */
"incremental": true /* インクリメンタルビルド */
},
"include": [
"src/**/*.ts",
"src/**/*.tsx"
],
"exclude": [
"node_modules",
"dist"
]
}

解説:
* target はバンドラが最終的なJSバージョンにトランスパイルすることを前提に、比較的新しいバージョン(es2020 など)を指定することが多いです。
* module はバンドラにES Modules形式で入力させるのが一般的なため esnext を指定します。
* lib にはブラウザ環境に必要な dom と、使用するES機能に応じたライブラリを指定します。
* jsx は使用するライブラリ(Reactなど)やバージョンに合わせて適切な値を指定します。
* sourceMap は開発時のデバッグに必須です。
* noEmit: true は、TypeScriptコンパイラが型チェックのみを行い、JavaScriptコードの生成はバンドラに任せる場合に設定します。バンドラによっては、TypeScriptコンパイラ自身にJSを生成させる場合もあるので、その場合は noEmit: false とし、outDir も適切に設定します。

3. ライブラリ開発向け

他のTypeScript/JavaScriptプロジェクトから利用されるnpmライブラリなどの設定です。

json
{
"compilerOptions": {
"target": "es2015", /* 互換性を考慮してやや古いターゲット (必要に応じて調整) */
"module": "esnext", /* 現代的なライブラリはESM形式で公開することが多い */
"lib": ["es2015"], /* ライブラリ自身の機能に必要なES機能のみ */
"strict": true, /* 厳格な型チェック */
"esModuleInterop": true, /* モジュール互換性 */
"forceConsistentCasingInFileNames": true, /* ファイル名の大文字小文字を区別 */
"declaration": true, /* 型定義ファイル (.d.ts) を生成 */
"sourceMap": true, /* デバッグ用にソースマップを生成 */
"outDir": "./dist", /* 出力ディレクトリ */
"rootDir": "./src", /* ソースディレクトリ */
"skipLibCheck": true /* 依存ライブラリの型チェックをスキップ */
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules",
"dist"
]
}

解説:
* target はライブラリのターゲットとする環境によって選択します。広く使われることを想定するなら es2015 などやや古いバージョンも検討しますが、多くの場合はバンドラが最終的なトランスパイルを行うため、より新しいバージョンでも構いません。
* module は、現代的なライブラリはES Modules形式で公開されることが多いため esnext がよく使われます。CommonJSやUMD形式も必要であれば、Rollupなどのバンドラで複数の形式で出力します。
* lib はライブラリ自身の機能に必要なES機能のみを含めます。DOMやNode.js固有のAPIに依存しないライブラリであれば、これらのライブラリは含めません。
* declaration: true はライブラリの型情報を利用者に提供するために必須です。
* outDir には、生成されたJSファイルと .d.ts ファイルが出力されます。package.jsonmain, module, types フィールドで、これらの出力先を指定します。

これらの例はあくまで一般的なものであり、具体的なプロジェクトの要件に応じて、tsconfig.json の設定はさらに詳細にカスタマイズする必要があります。tsc --init で生成されたファイルをベースに、必要なオプションを有効化し、値を調整していくのが良いでしょう。

まとめ

本記事では、TypeScriptプロジェクトの根幹となる tsconfig.json ファイルについて、tsc --init コマンドによる生成から始め、その基本的な構造と主要な設定オプションについて詳細に解説しました。

tsconfig.json は、単にコンパイル対象ファイルを指定するだけでなく、出力されるJavaScriptコードのバージョンやモジュールシステム、そして最も重要な型チェックの厳格さを制御するための中心的な設定ファイルです。特に compilerOptions セクションの target, module, lib オプションは実行環境やビルドシステムに合わせて適切に設定する必要があり、strict に関連する一連のオプションはコードの品質と信頼性を向上させる上で非常に重要です。

tsc --init コマンドは、これらの設定をゼロから記述する手間を省き、コメント付きのテンプレートを提供してくれる便利なツールです。しかし、生成されたファイルをそのまま使用するのではなく、プロジェクトの特性に合わせて各オプションの意味を理解し、適切にカスタマイズすることが、TypeScript開発を成功させるための鍵となります。

files, include, exclude によるコンパイル対象の指定、extends による設定の共通化、そしてモノレポにおける references によるプロジェクト参照といった機能も、プロジェクト管理の効率化に大きく貢献します。

TypeScriptのエコシステムは常に進化しており、新しいバージョンで tsconfig.json に新しいオプションが追加されたり、既存のオプションのデフォルト値や推奨される設定が変わったりすることがあります。そのため、定期的にTypeScriptの公式ドキュメントやリリースノートを確認し、プロジェクトの tsconfig.json 設定を見直すことも重要です。

適切な tsconfig.json 設定を行うことで、TypeScriptの恩恵を最大限に享受し、より堅牢で保守性の高いコード開発を進めることができるでしょう。本記事が、あなたのTypeScript学習の一助となれば幸いです。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール