tsconfig.jsonとは

tsconfig.jsonは、TypeScriptプロジェクトのルートディレクトリに配置される設定ファイルです。このファイルにより、TypeScriptコンパイラ(tsc)の動作を細かく制御し、プロジェクト全体のコンパイル方法を定義できます。

tsconfig.jsonの存在は、そのディレクトリがTypeScriptプロジェクトのルートであることを示します。適切なコンパイラオプションを設定することで、型安全性の向上、開発体験の改善、ビルドパフォーマンスの最適化を実現できます。

前提条件

この記事を読む上での前提条件は以下の通りです。

  • Node.js 18以上がインストールされていること
  • TypeScript 5.0以上がインストールされていること
  • TypeScriptの基本的な文法を理解していること

tsconfig.jsonの基本構造

tsconfig.jsonは以下のような構造を持ちます。

1
2
3
4
5
6
7
{
  "compilerOptions": {
    // コンパイラオプションをここに記述
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

compilerOptionsにはコンパイラの動作を制御するオプションを、includeexcludeにはコンパイル対象のファイルパターンを指定します。

主要なコンパイラオプションの解説

TypeScriptのコンパイラオプションは多数存在しますが、ここでは実務で頻繁に使用する主要なオプションを解説します。

targetオプション - コンパイル先のECMAScriptバージョン

targetオプションは、TypeScriptコードをどのECMAScriptバージョンにコンパイルするかを指定します。

1
2
3
4
5
{
  "compilerOptions": {
    "target": "ES2022"
  }
}

主な設定値と用途は以下の通りです。

target値 用途・対象環境
ES5 古いブラウザ(IE11など)をサポートする必要がある場合
ES2015/ES6 モダンブラウザ向け、クラス構文やアロー関数をそのまま出力
ES2020 動的インポートやBigIntをサポート
ES2022 トップレベルawaitやクラスフィールドをサポート
ESNext TypeScriptがサポートする最新のES機能を使用

targetの設定はlibオプションのデフォルト値にも影響します。例えば、target: "ES2022"を指定すると、自動的にES2022の組み込み型定義が利用可能になります。

1
2
// target: ES2022の場合、トップレベルawaitが使用可能
const data = await fetch('/api/data');

moduleオプション - モジュールシステムの指定

moduleオプションは、出力されるJavaScriptのモジュール形式を指定します。

1
2
3
4
5
{
  "compilerOptions": {
    "module": "NodeNext"
  }
}

主な設定値は以下の通りです。

module値 説明
CommonJS Node.jsの従来のモジュール形式(require/module.exports)
ES2015/ES6 ESモジュール形式(import/export)
ES2020 動的インポートとimport.metaをサポート
ES2022 トップレベルawaitをサポート
NodeNext Node.jsのモジュール解決に準拠(推奨)
Preserve 入力ファイルのモジュール形式を保持

モダンなNode.jsプロジェクトではNodeNextが推奨されます。これにより、package.jsonのtypeフィールドに基づいてCommonJSとESMを適切に切り替えられます。

1
2
3
4
5
6
{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext"
  }
}

moduleResolutionオプション - モジュール解決戦略

moduleResolutionオプションは、import文のモジュールパスをどのように解決するかを指定します。

1
2
3
4
5
{
  "compilerOptions": {
    "moduleResolution": "Bundler"
  }
}

主な設定値と用途は以下の通りです。

用途
Node10 従来のNode.jsのCommonJS向け(非推奨)
Node16/NodeNext Node.js v12以降のESMとCJSの両方をサポート
Bundler ViteやWebpackなどのバンドラーを使用する場合に推奨
Classic TypeScript 1.6以前の解決方法(非推奨)

バンドラーを使用するフロントエンドプロジェクトではBundlerを、Node.jsプロジェクトではNodeNextを使用することが推奨されます。

strictオプション - 厳格な型チェックの有効化

strictオプションは、TypeScriptの型チェックを厳格にするためのフラグです。trueに設定すると、複数の厳格なチェックオプションが一括で有効化されます。

1
2
3
4
5
{
  "compilerOptions": {
    "strict": true
  }
}

strict: trueにより有効化されるオプションは以下の通りです。

オプション 説明
strictNullChecks nullとundefinedを厳格にチェック
strictFunctionTypes 関数の引数の型を厳格にチェック
strictBindCallApply bind、call、applyの引数を厳格にチェック
strictPropertyInitialization クラスプロパティの初期化を必須化
noImplicitAny 暗黙的なany型を禁止
noImplicitThis 暗黙的なthisの型を禁止
alwaysStrict JavaScriptの"use strict"を常に出力
useUnknownInCatchVariables catch句の変数をunknown型に

新規プロジェクトでは必ずstrict: trueを設定することを強く推奨します。これにより、多くの潜在的なバグを事前に検出できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// strict: trueの場合、nullチェックが必須
function getLength(str: string | null): number {
  // エラー: Object is possibly 'null'
  // return str.length;
  
  // 正しい実装
  if (str === null) {
    return 0;
  }
  return str.length;
}

esModuleInteropオプション - CommonJSとESMの相互運用

esModuleInteropオプションは、CommonJSモジュールをESモジュール形式でインポートする際の互換性を改善します。

1
2
3
4
5
{
  "compilerOptions": {
    "esModuleInterop": true
  }
}

このオプションを有効にすると、デフォルトエクスポートを持たないCommonJSモジュールでも、以下のようなESM形式のインポートが可能になります。

1
2
3
4
5
// esModuleInterop: trueの場合
import express from 'express';

// esModuleInterop: falseの場合は以下のように書く必要がある
// import * as express from 'express';

esModuleInterop: trueを設定すると、allowSyntheticDefaultImportsも自動的に有効化されます。

resolveJsonModuleオプション - JSONファイルのインポート

resolveJsonModuleオプションを有効にすると、JSONファイルを直接インポートできるようになります。

1
2
3
4
5
{
  "compilerOptions": {
    "resolveJsonModule": true
  }
}

この設定により、以下のようにJSONファイルをインポートし、型推論の恩恵を受けることができます。

1
2
3
4
import config from './config.json';

// configの型は自動的にJSONの構造から推論される
console.log(config.apiUrl); // 型安全にアクセス可能

pathsオプション - パスエイリアスの設定

pathsオプションは、モジュールのインポートパスにエイリアスを設定できます。これにより、相対パスの記述を簡潔にできます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"],
      "@utils/*": ["./src/utils/*"]
    }
  }
}

この設定により、以下のようなインポートが可能になります。

1
2
3
4
5
// 相対パスを使用した場合
import { Button } from '../../../components/Button';

// pathsエイリアスを使用した場合
import { Button } from '@components/Button';

重要な注意点として、pathsはTypeScriptのコンパイル時の解決のみに影響し、実行時のパス解決には影響しません。実行時にもエイリアスを有効にするには、バンドラーやtsconfig-pathsなどのツールで別途設定が必要です。

推奨設定パターン

プロジェクトの種類に応じた推奨設定パターンを紹介します。

Node.jsプロジェクト向け設定

Node.js 20以上をターゲットにした推奨設定です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "resolveJsonModule": true,
    "noEmitOnError": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

フロントエンド(React/Vite)向け設定

ViteとReactを使用するフロントエンドプロジェクトの推奨設定です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "Bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src"]
}

ライブラリ開発向け設定

npmパッケージとして公開するライブラリの推奨設定です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,
    "declarationDir": "./dist/types",
    "declarationMap": true,
    "sourceMap": true,
    "composite": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

プロジェクトリファレンスの活用

プロジェクトリファレンスは、TypeScriptプロジェクトを複数の小さなプロジェクトに分割し、ビルド時間の短縮とコードの論理的な分離を実現する機能です。

プロジェクトリファレンスの基本構成

モノレポや大規模プロジェクトでの典型的な構成を示します。

project/
├── tsconfig.json           # ルート設定(ソリューション設定)
├── packages/
│   ├── core/
│   │   ├── src/
│   │   └── tsconfig.json
│   ├── utils/
│   │   ├── src/
│   │   └── tsconfig.json
│   └── app/
│       ├── src/
│       └── tsconfig.json

ルートのtsconfig.json(ソリューション設定)は以下のように構成します。

1
2
3
4
5
6
7
8
{
  "files": [],
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/utils" },
    { "path": "./packages/app" }
  ]
}

compositeオプションの設定

プロジェクトリファレンスを使用するには、参照される側のプロジェクトでcompositeオプションを有効にする必要があります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"]
}

composite: trueを設定すると、以下の制約が適用されます。

  • rootDirが未設定の場合、tsconfig.jsonを含むディレクトリがデフォルトになる
  • すべての実装ファイルはincludeパターンかfiles配列で指定される必要がある
  • declarationが自動的に有効化される

他プロジェクトの参照設定

他のプロジェクトを参照する側のtsconfig.jsonでは、referencesオプションを使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"],
  "references": [
    { "path": "../core" },
    { "path": "../utils" }
  ]
}

ビルドモードの使用

プロジェクトリファレンスを使用する場合、tsc --build(またはtsc -b)コマンドでビルドします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# ソリューション全体をビルド
tsc --build

# 特定のプロジェクトをビルド
tsc --build packages/app

# クリーンビルド
tsc --build --clean

# 強制的に全プロジェクトをリビルド
tsc --build --force

# ウォッチモード
tsc --build --watch

tsc --buildは依存関係を解析し、必要なプロジェクトのみを正しい順序でビルドします。これにより、大規模プロジェクトのビルド時間を大幅に短縮できます。

共通設定の継承

複数のプロジェクトで共通の設定を使用する場合、extendsオプションを使用して設定を継承できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// tsconfig.base.json(共通設定)
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// packages/core/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "composite": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"]
}

その他の重要なオプション

実務で知っておくと便利なオプションを紹介します。

skipLibCheckオプション

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

1
2
3
4
5
{
  "compilerOptions": {
    "skipLibCheck": true
  }
}

node_modules内の型定義ファイル間で型の不整合がある場合や、ビルド時間を短縮したい場合に有効です。ほとんどのプロジェクトでtrueに設定することが推奨されます。

isolatedModulesオプション

isolatedModulesは、各ファイルを独立したモジュールとしてトランスパイルできることを保証します。

1
2
3
4
5
{
  "compilerOptions": {
    "isolatedModules": true
  }
}

Babel、esbuild、swcなどの単一ファイルトランスパイラーを使用する場合に必須です。これにより、const enumや名前空間の一部機能が制限されますが、より高速なビルドが可能になります。

noEmitオプション

noEmitは、コンパイル時にJavaScriptファイルを出力しません。

1
2
3
4
5
{
  "compilerOptions": {
    "noEmit": true
  }
}

バンドラーがトランスパイルを行い、TypeScriptは型チェックのみに使用する場合に設定します。Viteなどを使用するフロントエンドプロジェクトで一般的です。

verbatimModuleSyntaxオプション

verbatimModuleSyntaxは、import/exportの構文をそのまま出力ファイルに反映します。

1
2
3
4
5
{
  "compilerOptions": {
    "verbatimModuleSyntax": true
  }
}

このオプションを有効にすると、型のみのインポートには明示的にimport typeを使用する必要があります。

1
2
3
4
5
// 型のみのインポートは明示的にimport typeを使用
import type { User } from './types';

// 値のインポート
import { getUser } from './api';

まとめ

tsconfig.jsonの適切な設定は、TypeScriptプロジェクトの開発体験と品質を大きく左右します。この記事で解説した主要なポイントは以下の通りです。

  1. strict: trueを必ず設定し、型安全性を最大限に活用する
  2. targetmoduleはプロジェクトの実行環境に合わせて適切に選択する
  3. Node.jsプロジェクトではmodule: "NodeNext"moduleResolution: "NodeNext"を使用する
  4. バンドラーを使用するフロントエンドプロジェクトではmoduleResolution: "Bundler"を使用する
  5. 大規模プロジェクトではプロジェクトリファレンスを活用してビルド時間を短縮する
  6. pathsエイリアスを使用してインポートパスを簡潔にする

プロジェクトの要件に応じて、この記事で紹介した推奨設定パターンをベースにカスタマイズしてください。

参考リンク