tsconfig.json完全ガイド〜推奨設定・strictモード・モノレポ・React/Node対応【2026年版】〜

TypeScriptを書いていて「tsconfig.jsonの設定項目が多すぎて、結局何をどう設定するのが正解なのか分からない」と感じたことはありませんか。strictmoduleResolutionverbatimModuleSyntaxnoUncheckedIndexedAccess……公式ドキュメントを読んでも、自分のプロジェクトに何を入れるべきかは正直見えてきません。

本記事はTypeScript 5.x準拠のtsconfig.json設定特化ガイドとして、40個以上のコピペで動く設定例とともに、最小構成からモノレポ・React/Next.js/Node.js/Deno/Bunまで、現場で使える推奨設定をすべてまとめます。型システムの記事(B01〜B09)が「型をどう書くか」だったのに対し、本記事は「環境とコンフィグをどう整えるか」に集中したコンフィグ専門の完全ガイドです。

この記事で得られること

  • tsconfig.jsonの最小構成から本番運用構成までの全段階
  • strict系8フラグの個別解説と推奨ON/OFF判断基準
  • moduleResolution: "bundler" など2026年標準の選び方
  • Vite + React / Next.js / Node.js / Deno / Bun それぞれの推奨設定
  • pnpm + Turborepoモノレポでのcomposite / Project References構成
  • ビルドが遅い・型エラーが消えない時のトラブルシュート手順
  1. tsconfig.jsonの最小構成と全体像
    1. tsc –init で出力される雛形
    2. 本当に最小限のtsconfig.json
    3. tsconfig.jsonが解決される順番
  2. extends で共通設定を一元化する
    1. ベースとなる tsconfig.base.json
    2. extends で継承する子tsconfig
    3. npm package として配布された設定を継承する
  3. target と lib: どのJSバージョンで動かすか
    1. targetの選び方
    2. libで読み込まれる型定義を制御する
  4. module / moduleResolution / moduleDetection
    1. moduleResolution: “Bundler” がほぼ正解
    2. Node.js ESM の場合は NodeNext
    3. moduleDetection で .ts ファイルをモジュール扱いに統一
  5. strict 系フラグ完全解説
    1. strict: true が有効にする8フラグ一覧
    2. strictNullChecks: null / undefined を別の型として扱う
    3. strictFunctionTypes: 関数引数の反変チェック
    4. noImplicitAny: 暗黙のanyを禁止する
  6. +α で必ず入れたい推奨フラグ
    1. noUncheckedIndexedAccess: 配列アクセスをundefined含みに
    2. noImplicitOverride: override キーワードを必須に
    3. noFallthroughCasesInSwitch: switch fall-through 禁止
    4. exactOptionalPropertyTypes: undefined と省略を区別
    5. useDefineForClassFields: クラスフィールドをdefineセマンティクスに
    6. verbatimModuleSyntax: import type を厳密化
  7. 互換系オプション: esModuleInterop と仲間たち
    1. esModuleInterop: CommonJSをimport defaultで取り扱う
    2. forceConsistentCasingInFileNames: 大文字小文字統一
    3. isolatedModules: ファイル単独でトランスパイル可能に
    4. allowImportingTsExtensions: .ts拡張子付きimport
    5. resolveJsonModule: JSONをimport可能に
  8. パス解決: paths / baseUrl / types
    1. baseUrl + paths でエイリアス設定
    2. types / typeRoots: 読み込む型定義を絞る
  9. include / exclude / files の使い分け
    1. include: globで対象指定(基本)
    2. files: 完全列挙(ライブラリ向け)
    3. テスト用と本番用でtsconfigを分ける
  10. composite / Project References でモノレポ対応
    1. ルートtsconfigはsolution専用にする
    2. 各パッケージは composite: true を付ける
    3. –build モードで参照解決込みビルド
  11. Vite + React 推奨tsconfig
    1. ルートtsconfig.json: solution専用
    2. tsconfig.app.json: アプリ本体用
    3. tsconfig.node.json: ビルド設定ファイル用
  12. Next.js 推奨tsconfig
    1. Next.js App Router 標準構成
  13. Node.js 純粋運用の推奨tsconfig
    1. Node.js ESM + tsx 開発の標準構成
    2. package.json を ESM に揃える
  14. Deno / Bun 対応
    1. Deno: deno.json 内に compilerOptions
    2. Bun: 拡張tsconfig対応
  15. incremental / watch でビルドを高速化
    1. incremental: 差分ビルドキャッシュ
    2. tsc –watch でファイル監視
    3. watchOptions で監視方式を切替
  16. パフォーマンスチューニング
    1. skipLibCheck: ライブラリ型チェックをスキップ
    2. types を明示して読み込みを絞る
    3. tsc –diagnostics でボトルネック特定
  17. トラブルシュート: よくあるエラーと対処
    1. Cannot find module ‘X’ or its corresponding type declarations
    2. moduleResolution の不整合: バンドラとtscでpathが解決できない
    3. JSX要素タグが型エラー: jsxの設定ミス
    4. Composite projects must have rootDir specified
  18. pnpm + Turborepoモノレポ実例
    1. ルート構造
    2. 共通tsconfigパッケージを切る
    3. 各パッケージから継承
    4. Turborepo のパイプライン
  19. 2026年版・推奨設定総まとめ
    1. Webアプリ用フル装備版
    2. Node.js サーバ用フル装備版
  20. まとめと次に読みたい記事

tsconfig.jsonの最小構成と全体像

まずは「何も書かない」状態から始めて、段階的に項目を足していきます。tsconfig.jsonは大きくcompilerOptions(コンパイラ動作)とinclude / exclude / files(対象ファイル指定)の2ブロックに分かれています。

tsc –init で出力される雛形

新規プロジェクトでは必ずこのコマンドから始めましょう。コメント付きで全項目が並んだ巨大なtsconfig.jsonが生成されます。

# tsc本体をインストール
npm install -D typescript

# 雛形生成(コメント大量入り)
npx tsc --init

# よく使うフラグを最初から指定して生成
npx tsc --init --target ES2022 --module ESNext --strict --moduleResolution bundler

本当に最小限のtsconfig.json

すべてのフラグが省略可能ですが、現実には次の5項目を書けば動くプロジェクトの98%は成立します。

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src/**/*"]
}

tsconfig.jsonが解決される順番

tscは現在ディレクトリ→親→さらに親、と順にtsconfig.jsonを探します。明示的に別ファイルを使いたい場合は-p(または--project)を渡します。

# デフォルト: カレントの tsconfig.json を使用
npx tsc

# 別ファイル指定
npx tsc -p tsconfig.build.json

# ディレクトリ指定(中の tsconfig.json を読む)
npx tsc -p ./packages/web

extends で共通設定を一元化する

モノレポ・複数環境を扱う前に、まずextendsの仕組みを理解しておくと後がラクになります。tsconfigは継承でき、共通項目をベースファイルに切り出せます。

ベースとなる tsconfig.base.json

// tsconfig.base.json
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022"],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "isolatedModules": true,
    "resolveJsonModule": true
  }
}

extends で継承する子tsconfig

// tsconfig.json (アプリ用)
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "outDir": "./dist"
  },
  "include": ["src/**/*"]
}

npm package として配布された設定を継承する

tsconfig.jsonはnode_modules内のtsconfigも継承できます。公式の@tsconfig/*パッケージを使うとベース設定をメンテせずに済みます。

# 公式の推奨ベース設定(Node.js 20向け)をインストール
npm install -D @tsconfig/node20

# Strictest版(全フラグ最大)を入れたい場合
npm install -D @tsconfig/strictest
// tsconfig.json
{
  "extends": ["@tsconfig/strictest/tsconfig.json", "@tsconfig/node20/tsconfig.json"],
  "compilerOptions": {
    "outDir": "./dist"
  },
  "include": ["src/**/*"]
}

target と lib: どのJSバージョンで動かすか

tsconfigで最初に決めるべきは「どのJavaScriptランタイムをターゲットにするか」です。targetがコンパイル後のJS文法のバージョン、libがコード内で参照可能なグローバル型の集合を表します。

targetの選び方

2026年時点でES2022がほぼデフォルトです。Node.js 18以降・全モダンブラウザがES2022を完全サポートしています。

// 2026年の標準的なtarget
{
  "compilerOptions": {
    "target": "ES2022"
  }
}
// IE11 等の古いブラウザサポートが必要な場合のみES5
{
  "compilerOptions": {
    "target": "ES5",
    "downlevelIteration": true
  }
}

libで読み込まれる型定義を制御する

libはTypeScriptがビルトインで持っているグローバル型ファイル(lib.dom.d.tsなど)の中から、どれを読み込むかを指定します。Node.js専用プロジェクトでDOM型が補完に出てくる問題は、たいていここで解決します。

// ブラウザ向け
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"]
  }
}
// Node.js 専用(DOMを除外して document などを補完に出さない)
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022"]
  }
}
// Web Worker向け
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "WebWorker", "WebWorker.Iterable"]
  }
}

module / moduleResolution / moduleDetection

ここがtsconfigで最もつまずきやすい3点セットです。2026年の正解は「バンドラを使うかランタイムESMで直接走らせるかで切り替える」です。

moduleResolution: “Bundler” がほぼ正解

Vite / webpack / esbuild / Rollup / Next.js などのバンドラを通すなら、moduleResolution: "Bundler"がTypeScript 5.0以降の推奨です。拡張子なしimportやpackage.jsonのexportsフィールドを自然に解決します。

// Vite / Next.js / webpack を使うWebアプリ
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "Bundler"
  }
}

Node.js ESM の場合は NodeNext

バンドラを通さずNode.jsで直接ESMとして実行するならNodeNextを使います。この場合、importは必ず拡張子.js付きで書く必要があります。

// Node.js ESM 純粋実行
{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext"
  }
}
// ✅ NodeNextでは拡張子.js付きで書く(.tsではなく.js)
import { greet } from "./greet.js";

// ❌ 拡張子なしや.tsはNodeNextでは解決できない
// import { greet } from "./greet";

moduleDetection で .ts ファイルをモジュール扱いに統一

importもexportも書いていない.tsファイルが「グローバルスクリプト」と判定されると、思わぬ名前衝突が発生します。moduleDetection: "force"で全ファイルを強制的にESモジュールとして扱えます。

{
  "compilerOptions": {
    "moduleDetection": "force"
  }
}

strict 系フラグ完全解説

strict: trueは8つのフラグを一括ONにするマクロです。新規プロジェクトでは必ずONから始めてください。後からONにすると数百件のエラーが噴出します。

strict: true が有効にする8フラグ一覧

// strict: true が暗黙的に有効にするもの
{
  "compilerOptions": {
    "strict": true
    // ↓ 以下が自動でtrueになる
    // "noImplicitAny": true,
    // "strictNullChecks": true,
    // "strictFunctionTypes": true,
    // "strictBindCallApply": true,
    // "strictPropertyInitialization": true,
    // "noImplicitThis": true,
    // "useUnknownInCatchVariables": true,
    // "alwaysStrict": true
  }
}

strictNullChecks: null / undefined を別の型として扱う

// strictNullChecks: true の世界
function getLength(s: string): number {
  return s.length;
}

const value: string | null = Math.random() > 0.5 ? "hello" : null;

// ❌ コンパイルエラー: 'string | null' は 'string' に渡せない
// getLength(value);

// ✅ ナローイングしてから渡す
if (value !== null) {
  getLength(value);
}

strictFunctionTypes: 関数引数の反変チェック

// strictFunctionTypes: true で防げるバグ
type Animal = { name: string };
type Dog = Animal & { bark(): void };

let animalFn: (a: Animal) => void;
let dogFn: (d: Dog) => void = (d) => d.bark();

// ❌ コンパイルエラー: Dog前提の関数をAnimal用に代入できない
// animalFn = dogFn;

noImplicitAny: 暗黙のanyを禁止する

// noImplicitAny: true
// ❌ コンパイルエラー: 引数 x の型が暗黙的に any
// function double(x) { return x * 2; }

// ✅ 明示的に型注釈
function double(x: number) {
  return x * 2;
}

+α で必ず入れたい推奨フラグ

strict: trueに含まれない強化フラグの中で、新規プロジェクトに無条件で入れるべきものを6つ紹介します。

noUncheckedIndexedAccess: 配列アクセスをundefined含みに

これを入れると、array[0]の戻り値の型がTではなくT | undefinedになります。実行時のCannot read property of undefinedを激減させる最強フラグです。

// noUncheckedIndexedAccess: true
const arr: string[] = ["a", "b", "c"];

// arr[0] の型は string | undefined になる
const first = arr[0]; // string | undefined

// ❌ undefined の可能性があるので直接呼べない
// first.toUpperCase();

// ✅ ガードしてから使う
if (first !== undefined) {
  first.toUpperCase();
}

noImplicitOverride: override キーワードを必須に

// noImplicitOverride: true
class Base {
  greet() { console.log("hi"); }
}

class Child extends Base {
  // ❌ overrideキーワードがないとエラー
  // greet() { console.log("bonjour"); }

  // ✅ override必須で意図が明確
  override greet() {
    console.log("bonjour");
  }
}

noFallthroughCasesInSwitch: switch fall-through 禁止

// noFallthroughCasesInSwitch: true
function handle(n: number) {
  switch (n) {
    case 1:
      console.log("one");
      // ❌ break / return がない → エラー
    case 2:
      console.log("two");
      break;
  }
}

exactOptionalPropertyTypes: undefined と省略を区別

// exactOptionalPropertyTypes: true
type User = { name?: string };

// ✅ プロパティ自体を省略
const a: User = {};
// ✅ 文字列を入れる
const b: User = { name: "Alice" };
// ❌ 明示的にundefinedを入れるのはエラー
// const c: User = { name: undefined };

useDefineForClassFields: クラスフィールドをdefineセマンティクスに

// useDefineForClassFields: true (ES2022以降の標準動作)
class Foo {
  // [[Define]] セマンティクス: フィールドは Object.defineProperty で初期化
  count = 0;
}

verbatimModuleSyntax: import type を厳密化

TypeScript 5.0で導入された新フラグ。import typeと通常importを明確に分離し、ビルド時に型のみのimportを完全削除します。

// verbatimModuleSyntax: true
import type { User } from "./types";  // 型のみ → 出力から消える
import { fetchUser } from "./api";    // 値 → 出力に残る

// ❌ 型と値を混在させるとエラー
// import { User, fetchUser } from "./api";

互換系オプション: esModuleInterop と仲間たち

CommonJSとESMの行き来で発生する地獄を整理します。

esModuleInterop: CommonJSをimport defaultで取り扱う

{
  "compilerOptions": {
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  }
}
// esModuleInterop: true でこう書ける
import express from "express";  // ✅
import React from "react";       // ✅

// esModuleInterop: false だとこう書く必要がある
// import * as express from "express";

forceConsistentCasingInFileNames: 大文字小文字統一

WindowsとmacOS/Linuxで挙動が分かれる最悪のバグの源を防ぎます。必ずONにしてください。

{
  "compilerOptions": {
    "forceConsistentCasingInFileNames": true
  }
}

isolatedModules: ファイル単独でトランスパイル可能に

esbuild / SWC / Babelなどtscを通さないトランスパイラを使う場合に必須。tscが「複数ファイル参照」を前提とする機能(const enum等)を禁止します。

{
  "compilerOptions": {
    "isolatedModules": true
  }
}

allowImportingTsExtensions: .ts拡張子付きimport

Deno / Bun / Vite ではtsファイルを直接拡張子付きでimportしたいケースがあります。

{
  "compilerOptions": {
    "allowImportingTsExtensions": true,
    "noEmit": true
  }
}
// allowImportingTsExtensions: true
import { greet } from "./greet.ts"; // ✅

resolveJsonModule: JSONをimport可能に

{
  "compilerOptions": {
    "resolveJsonModule": true
  }
}
// resolveJsonModule: true
import packageJson from "./package.json";
console.log(packageJson.version);

パス解決: paths / baseUrl / types

大規模プロジェクトでは../../../utils/fooのような相対パス地獄が必ず発生します。pathsでエイリアスを設定しましょう。

baseUrl + paths でエイリアス設定

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"],
      "@lib/*": ["src/lib/*"],
      "@types/*": ["src/types/*"]
    }
  }
}
// 相対パス地獄
// import { Button } from "../../../components/Button";

// ✅ エイリアスでフラットに
import { Button } from "@components/Button";
import { fetcher } from "@lib/fetcher";
注意: pathsはtscの型解決だけ整え、実行時のimport解決はバンドラ側で同等の設定をしないと動きません。Vite ならvite-tsconfig-paths、Jest ならjest.configmoduleNameMapperでも揃えてください。

types / typeRoots: 読み込む型定義を絞る

typesを指定すると、その配列にあるパッケージの型しか自動読み込みされなくなります。ビルド速度改善にも有効です。

{
  "compilerOptions": {
    "types": ["node", "vite/client"]
  }
}
// 自前の型定義フォルダを追加
{
  "compilerOptions": {
    "typeRoots": ["./node_modules/@types", "./src/types"]
  }
}

include / exclude / files の使い分け

tsconfigで処理対象を絞る3つの方法を整理します。

include: globで対象指定(基本)

{
  "include": [
    "src/**/*",
    "tests/**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "dist",
    "**/*.spec.ts"
  ]
}

files: 完全列挙(ライブラリ向け)

{
  "files": [
    "src/index.ts",
    "src/types.d.ts"
  ]
}

テスト用と本番用でtsconfigを分ける

// tsconfig.json (エディタ・型チェック用: すべて含む)
{
  "extends": "./tsconfig.base.json",
  "include": ["src/**/*", "tests/**/*"]
}
// tsconfig.build.json (ビルド用: テスト除外)
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "declaration": true
  },
  "include": ["src/**/*"],
  "exclude": ["**/*.test.ts", "**/*.spec.ts"]
}

composite / Project References でモノレポ対応

pnpm / Turborepo / Nx などのモノレポでは、Project Referencesを使うとパッケージ単位での増分ビルド・型チェックが可能になります。

ルートtsconfigはsolution専用にする

// /tsconfig.json (ルート: solution-style)
{
  "files": [],
  "references": [
    { "path": "./packages/shared" },
    { "path": "./packages/api" },
    { "path": "./packages/web" }
  ]
}

各パッケージは composite: true を付ける

// /packages/shared/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "tsBuildInfoFile": "./dist/.tsbuildinfo"
  },
  "include": ["src/**/*"]
}
// /packages/web/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "composite": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"],
  "references": [
    { "path": "../shared" }
  ]
}

–build モードで参照解決込みビルド

# ルートから一気にビルド(依存順を解決)
npx tsc --build

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

# 強制再ビルド
npx tsc --build --force

# 並列ビルド+ファイル監視
npx tsc --build --watch

Vite + React 推奨tsconfig

Vite公式テンプレが採用しているtsconfig分割パターンを解説します。アプリ用とNode用(vite.config.ts用)を分けるのが正解です。

ルートtsconfig.json: solution専用

// tsconfig.json
{
  "files": [],
  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ]
}

tsconfig.app.json: アプリ本体用

// tsconfig.app.json
{
  "compilerOptions": {
    "composite": true,
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "target": "ES2022",
    "useDefineForClassFields": true,
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
    "isolatedModules": true,
    "skipLibCheck": true
  },
  "include": ["src"]
}

tsconfig.node.json: ビルド設定ファイル用

// tsconfig.node.json
{
  "compilerOptions": {
    "composite": true,
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
    "target": "ES2022",
    "lib": ["ES2023"],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true
  },
  "include": ["vite.config.ts"]
}

Next.js 推奨tsconfig

Next.js 14+ はcreate-next-appが自動でtsconfig.jsonを生成しますが、ポイントを押さえて手動でも書けるようにしておきましょう。

Next.js App Router 標準構成

// tsconfig.json (Next.js App Router)
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      { "name": "next" }
    ],
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    ".next/types/**/*.ts"
  ],
  "exclude": ["node_modules"]
}
Next.js特有のポイント: "jsx": "preserve"になっているのは、Next.jsが内部のSWCでJSX変換を行うためです。tsc側ではJSXを残します。

Node.js 純粋運用の推奨tsconfig

サーバサイドコードをNode.jsで直接実行する場合の構成です。バンドラを通さない分、設定がシビアです。

Node.js ESM + tsx 開発の標準構成

// tsconfig.json (Node.js + tsx)
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022"],
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "types": ["node"]
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

package.json を ESM に揃える

// package.json
{
  "type": "module",
  "main": "./dist/index.js",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsx watch src/index.ts",
    "typecheck": "tsc --noEmit"
  },
  "devDependencies": {
    "@types/node": "^20.11.0",
    "tsx": "^4.7.0",
    "typescript": "^5.4.0"
  }
}

Deno / Bun 対応

新世代ランタイムでは、TypeScriptをそのまま実行できます。tsconfigの位置付けが少し変わるので押さえておきましょう。

Deno: deno.json 内に compilerOptions

// deno.json
{
  "compilerOptions": {
    "strict": true,
    "lib": ["deno.window", "esnext"],
    "jsx": "react-jsx",
    "jsxImportSource": "react"
  },
  "imports": {
    "react": "npm:react@^18.3.0"
  }
}
# Denoは設定なしでもTypeScriptを直接実行
deno run --allow-net main.ts

# deno.json の設定を明示
deno run --config deno.json --allow-net main.ts

Bun: 拡張tsconfig対応

// tsconfig.json (Bun向け)
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "noEmit": true,
    "strict": true,
    "types": ["bun-types"],
    "jsx": "react-jsx"
  }
}
# Bunで直接実行
bun run src/index.ts

# bun-typesをインストール
bun add -d bun-types

incremental / watch でビルドを高速化

TypeScriptのビルドが遅いと感じたら、まずincrementalを検討してください。

incremental: 差分ビルドキャッシュ

{
  "compilerOptions": {
    "incremental": true,
    "tsBuildInfoFile": "./node_modules/.cache/.tsbuildinfo"
  }
}

tsc –watch でファイル監視

# 変更検知して再コンパイル
npx tsc --watch

# 型チェックのみ・watch
npx tsc --noEmit --watch

# 監視オプションのチューニング
npx tsc --watch --preserveWatchOutput

watchOptions で監視方式を切替

{
  "watchOptions": {
    "watchFile": "useFsEvents",
    "watchDirectory": "useFsEvents",
    "fallbackPolling": "dynamicPriority",
    "synchronousWatchDirectory": false,
    "excludeDirectories": ["node_modules", "dist"]
  }
}

パフォーマンスチューニング

大規模プロジェクトでtscが遅くなったときの定番3手を順に挙げます。

skipLibCheck: ライブラリ型チェックをスキップ

node_modulesの.d.tsはライブラリ作者が責任を持つ前提で、自分のプロジェクトのチェック対象から外します。ほぼすべてのプロジェクトでONを推奨

{
  "compilerOptions": {
    "skipLibCheck": true
  }
}

types を明示して読み込みを絞る

// すべての @types/* を読まず必要なものだけに絞る
{
  "compilerOptions": {
    "types": ["node", "vitest/globals"]
  }
}

tsc –diagnostics でボトルネック特定

# コンパイル時間の内訳を表示
npx tsc --diagnostics

# さらに詳細な統計
npx tsc --extendedDiagnostics

# トレース出力(JSON)
npx tsc --generateTrace ./trace

トラブルシュート: よくあるエラーと対処

Cannot find module ‘X’ or its corresponding type declarations

# 1. 型定義パッケージを入れる
npm install -D @types/X

# 2. それでも見つからない場合は自前で宣言
echo "declare module 'X';" > src/types/X.d.ts
// src/types/global.d.ts に書く
declare module "untyped-package" {
  export function doSomething(input: string): number;
}

moduleResolution の不整合: バンドラとtscでpathが解決できない

# tsc側のpaths解決テスト
npx tsc --traceResolution > resolve.log

# Vite側はvite-tsconfig-pathsで揃える
npm install -D vite-tsconfig-paths
// vite.config.ts
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  plugins: [tsconfigPaths()],
});

JSX要素タグが型エラー: jsxの設定ミス

// React 17以降の新JSX変換を使う場合
{
  "compilerOptions": {
    "jsx": "react-jsx"
  }
}

Composite projects must have rootDir specified

// composite: true には rootDir が必須
{
  "compilerOptions": {
    "composite": true,
    "rootDir": "./src",
    "outDir": "./dist"
  }
}

pnpm + Turborepoモノレポ実例

2026年のモノレポ標準であるpnpm workspaces + Turborepoでのtsconfig運用を一気通貫で示します。

ルート構造

my-monorepo/
├── package.json
├── pnpm-workspace.yaml
├── turbo.json
├── tsconfig.base.json
├── tsconfig.json
└── packages/
    ├── tsconfig/
    │   ├── package.json
    │   ├── base.json
    │   ├── react.json
    │   └── node.json
    ├── shared/
    │   ├── package.json
    │   └── tsconfig.json
    ├── api/
    │   ├── package.json
    │   └── tsconfig.json
    └── web/
        ├── package.json
        └── tsconfig.json

共通tsconfigパッケージを切る

// packages/tsconfig/package.json
{
  "name": "@myrepo/tsconfig",
  "version": "0.0.0",
  "private": true,
  "files": ["base.json", "react.json", "node.json"]
}
// packages/tsconfig/base.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022"],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "declaration": true,
    "declarationMap": true,
    "incremental": true
  }
}
// packages/tsconfig/react.json
{
  "extends": "./base.json",
  "compilerOptions": {
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "jsx": "react-jsx"
  }
}

各パッケージから継承

// packages/web/tsconfig.json
{
  "extends": "@myrepo/tsconfig/react.json",
  "compilerOptions": {
    "composite": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "tsBuildInfoFile": "./.cache/.tsbuildinfo"
  },
  "include": ["src/**/*"],
  "references": [
    { "path": "../shared" }
  ]
}

Turborepo のパイプライン

// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "typecheck": {
      "dependsOn": ["^build"],
      "outputs": [".cache/.tsbuildinfo"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}
# モノレポ全体ビルド
pnpm turbo run build

# 型チェックだけ実行
pnpm turbo run typecheck

# 影響範囲だけ再ビルド
pnpm turbo run build --filter=...[HEAD^]

2026年版・推奨設定総まとめ

最後に、ここまでの知見をすべて反映した2026年版「迷ったらコレ」tsconfigを貼っておきます。コピペしてプロジェクトに合わせ微調整してください。

Webアプリ用フル装備版

// tsconfig.json (Vite/Next.js/webpack いずれもベースに使える)
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "moduleDetection": "force",
    "jsx": "react-jsx",
    "useDefineForClassFields": true,

    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,

    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "verbatimModuleSyntax": true,
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,

    "noEmit": true,
    "skipLibCheck": true,
    "incremental": true,
    "tsBuildInfoFile": "./node_modules/.cache/.tsbuildinfo",

    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src/**/*", "vite.config.ts"],
  "exclude": ["node_modules", "dist", "build"]
}

Node.js サーバ用フル装備版

// tsconfig.json (Node.js + ESM + tsx)
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022"],
    "module": "NodeNext",
    "moduleResolution": "NodeNext",

    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,

    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "resolveJsonModule": true,

    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "skipLibCheck": true,
    "incremental": true,
    "tsBuildInfoFile": "./node_modules/.cache/.tsbuildinfo",

    "types": ["node"]
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

まとめと次に読みたい記事

tsconfig.jsonは「公式ドキュメントを読んでも結局どう書けば良いか分からない」項目の代表でした。本記事のポイントを4行で振り返ります。

2026年版 tsconfig 4箇条

  • strict: true + noUncheckedIndexedAccessは新規プロジェクトで例外なくON
  • バンドラを使うならmoduleResolution: "Bundler"+module: "ESNext"
  • Node.jsで直接走らせるならNodeNext+importは.js拡張子
  • モノレポはcomposite + Project References+共通tsconfigパッケージ

型システム側の理解を深めたい方は、当サイトのB01〜B09シリーズ(TypeScript型基礎ジェネリクスUtility Types型ガードMapped Types型推論)を合わせて読むと、型と環境の両輪が揃います。tsconfigはプロジェクトの土台です。最初に時間をかけて整えるほど、その後のすべての開発体験が滑らかになります。

TypeScriptをさらに体系的に学びたい方へ
独学で詰まりがちなフロントエンド・TypeScript・モダンReact開発を、現役エンジニアのメンター付きで最短ルートに乗せたい方は、テックアカデミー侍エンジニアDMM WEBCAMPなどのオンラインスクールで、まず無料カウンセリングを試すのがおすすめです。実務でTypeScriptを使う案件を探すなら、レバテックフリーランスなどのIT特化エージェントで市場感を確認してみてください。

コメント

タイトルとURLをコピーしました