TypeScriptを書いていて「tsconfig.jsonの設定項目が多すぎて、結局何をどう設定するのが正解なのか分からない」と感じたことはありませんか。strict、moduleResolution、verbatimModuleSyntax、noUncheckedIndexedAccess……公式ドキュメントを読んでも、自分のプロジェクトに何を入れるべきかは正直見えてきません。
本記事は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構成 - ビルドが遅い・型エラーが消えない時のトラブルシュート手順
- tsconfig.jsonの最小構成と全体像
- extends で共通設定を一元化する
- target と lib: どのJSバージョンで動かすか
- module / moduleResolution / moduleDetection
- strict 系フラグ完全解説
- +α で必ず入れたい推奨フラグ
- 互換系オプション: esModuleInterop と仲間たち
- パス解決: paths / baseUrl / types
- include / exclude / files の使い分け
- composite / Project References でモノレポ対応
- Vite + React 推奨tsconfig
- Next.js 推奨tsconfig
- Node.js 純粋運用の推奨tsconfig
- Deno / Bun 対応
- incremental / watch でビルドを高速化
- パフォーマンスチューニング
- トラブルシュート: よくあるエラーと対処
- pnpm + Turborepoモノレポ実例
- 2026年版・推奨設定総まとめ
- まとめと次に読みたい記事
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.configのmoduleNameMapperでも揃えてください。
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"]
}
"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行で振り返ります。
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・モダンReact開発を、現役エンジニアのメンター付きで最短ルートに乗せたい方は、テックアカデミー・侍エンジニア・DMM WEBCAMPなどのオンラインスクールで、まず無料カウンセリングを試すのがおすすめです。実務でTypeScriptを使う案件を探すなら、レバテックフリーランスなどのIT特化エージェントで市場感を確認してみてください。

コメント