tsconfig と strict を読む — TypeScript Tips
TypeScript の挙動は tsconfig.json がスイッチ です。特に strict は複数の厳格チェックをまとめて有効にします。学習・小規模 CLI 向けの最小構成と、主要オプションと strict の内訳です。
参考: TypeScript — tsconfig.json · TypeScript — strict · TypeScript — Compiler Options
目次
- tsconfig.json の役割
- ファイルの置き場所と include
- よく触る compilerOptions
- strict が有効にするもの
- 実用的な最小 tsconfig
- オプションと症状の対応表
- 詰まりやすい点
tsconfig.json の役割
tsc(TypeScript コンパイラ)とエディタの型チェックは、同じ tsconfig.json を参照します。プロジェクトルートに1つ置くのが基本です。
flowchart LR TS["*.ts ソース"] CFG["tsconfig.json"] TSC["tsc / エディタ"] TS --> TSC CFG --> TSC| 役割 | 説明 |
|---|---|
| 対象ファイルの範囲 | include / exclude |
| 出力形式 | target, module, outDir |
| 型の厳しさ | strict および個別フラグ |
| モジュール解決 | moduleResolution, paths など |
「設定なしで TypeScript」は実質ありません。空のプロジェクトでも 意図した tsconfig を書く ことが出発点です。
ファイルの置き場所と include
{ "include": ["src"], "exclude": ["node_modules", "dist"]}include: 型チェック・コンパイル対象の globexclude: 除外(省略時もnode_modulesは大抵除外される)
src/index.ts だけを対象にするなら "include": ["src"] で足ります。テストを別フォルダに置くときは "include": ["src", "tests"] のように広げます。
ルートに tsconfig を置く理由
エディタは開いているファイルから上に辿って tsconfig.json を探します。サブフォルダだけに置くと、ルートのファイルがプロジェクト外扱いになることがあります。
よく触る compilerOptions
target
出力する JavaScript の言語レベルです。学習用なら ES2022 前後が無難です。
"target": "ES2022"module と moduleResolution
Node で ES モジュール(import / export)を使うなら ペアで 揃えます。
"module": "NodeNext","moduleResolution": "NodeNext"package.json に "type": "module" がある前提です。従来の構成には CommonJS と旧式の node(現在の名称は node10)の組み合わせもありますが、新規の Node.js プロジェクトでは NodeNext を基本にします。
rootDir と outDir
"rootDir": "src","outDir": "dist"ソースは src/、コンパイル結果は dist/ に出す、という整理です。型チェックだけ(noEmit: true)なら outDir は実行時には使いませんが、将来 tsc で吐き出すときのために書いておくとよいです。
noEmit
"noEmit": true型チェックだけ行い、JS ファイルを生成しない 設定です。実行は tsx や node(コンパイル後)に任せる構成でよく使います。
skipLibCheck
"skipLibCheck": truenode_modules 内の .d.ts の型矛盾をスキップし、チェックを速くします。学習・小規模プロジェクトでは true で問題ないことが多いです。
strict が有効にするもの
"strict": true は次のオプションを まとめて true にするショートカットです。
| フラグ | ざっくりした意味 |
|---|---|
strictNullChecks |
null / undefined を型から区別 |
strictFunctionTypes |
関数型の引数を厳密にチェック |
strictBindCallApply |
bind / call / apply の型を厳密に |
strictPropertyInitialization |
クラスプロパティの初期化を要求 |
noImplicitAny |
暗黙の any を禁止 |
noImplicitThis |
this の型が曖昧ならエラー |
alwaysStrict |
出力 JS に "use strict" |
useUnknownInCatchVariables |
catch した値を any ではなく unknown として扱う |
strictBuiltinIteratorReturn |
組み込みイテレータの完了時の戻り値型を厳密に扱う |
初心者にいちばん効くのは strictNullChecks と noImplicitAny です。strict: true を付けておけば、これらも含まれます。TypeScript の更新で strict 配下のチェックが追加されることもあるため、バージョン更新時にはリリースノートも確認します。
strictNullChecks の例
function printLength(s: string) { console.log(s.length);}const value: string | null = null;printLength(value); // エラー: null の可能性strict なしだと null がそのまま渡せて、実行時に落ちる可能性があります。コンパイル時に止められるのが TypeScript の価値です。
noImplicitAny の例
function add(a, b) { return a + b;}引数に型がないと any 扱いになり、strict ではエラーになります。明示的に書きます。
function add(a: number, b: number): number { return a + b;}個別に緩めたいときは strict: true のまま "noImplicitAny": false のように 上書き できます。ただし学習段階では strict: true 一本で慣れる方が後々楽です。
実用的な最小 tsconfig
Node + TypeScript 学習用のコピペ例です。
{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "noEmit": true, "skipLibCheck": true, "rootDir": "src", "outDir": "dist", "esModuleInterop": true, "forceConsistentCasingInFileNames": true }, "include": ["src"]}| オプション | この例での意図 |
|---|---|
strict |
型の穴を減らす |
noEmit |
tsc はチェック専用 |
esModuleInterop |
import fs from "fs" などが書きやすい |
forceConsistentCasingInFileNames |
ファイル名の大文字小文字ミスを検出(Windows でも有効) |
確認コマンド
npx tsc --noEmitpackage.json の scripts に "typecheck": "tsc --noEmit" を入れておくと便利です。
オプションと症状の対応表
| エラーや症状 | 関連しがちな設定 |
|---|---|
Object is possibly 'null' |
strictNullChecks(strict に含まれる) |
| 引数に型がないとエラー | noImplicitAny |
import が解決できない |
module / moduleResolution、拡張子 .js の要否(NodeNext) |
パスエイリアス @/ が効かない |
paths + baseUrl(別途設定が必要) |
| チェックが遅い | skipLibCheck: true |
| JS が出力されない | noEmit: true になっていないか確認 |
flowchart TB subgraph strict_block["strict: true"] SN["strictNullChecks"] NA["noImplicitAny"] Others["その他 strict* フラグ"] end CFG["tsconfig.json"] --> strict_block CFG --> MOD["module / moduleResolution"] CFG --> EMIT["noEmit / outDir"]詰まりやすい点
| 症状 | 対処 |
|---|---|
エディタと tsc で結果が違う |
エディタが別の tsconfig を見ていないか。ワークスペースルートを開く |
Cannot find module './foo' |
NodeNext では相対 import に拡張子が要る場合あり。./foo.js(出力後の名前)を指定 |
全部 any になっている |
checkJs や // @ts-nocheck、暗黙 any。strict と明示的な型注釈を確認 |
strict を外したらエラーが消えた |
一時しのぎにはなるが、実行時バグが増えやすい。該当箇所に正しい型を足す |
| サブフォルダだけ別設定にしたい | tsconfig.build.json を extends で継承 |
| JSON のコメントでパースエラー | tsconfig.json はコメント可。.json として厳密なツールには注意 |
extends で公式や社内のベースを継承するのも定番です。
{ "extends": "./tsconfig.base.json", "compilerOptions": { "outDir": "dist" }, "include": ["src"]}