Menu

TypeScriptのstrictモード: strict: true で有効になるチェック

tsconfig.json の strict: true は、noImplicitAny、strictNullChecks、strictPropertyInitialization など一連の型チェックを有効にします。それぞれが何を検出するか、既存のプロジェクトで strict モードを有効にする方法、strict に含まれない便利なフラグを解説します。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

strict モードとは、tsconfig.json の "strict": true オプションのことです。暗黙の any、チェックされない null と undefined、安全でない関数の代入、初期化されないクラスのフィールドを検出する8つの型チェックのフラグを、ひとつのスイッチでまとめて切り替えます。TypeScript 7 では strict はデフォルトで有効です。strict を通るコードは次のようになります:

出力は no user、SyntaxError、42 です。: number、?.、instanceof のチェックのどれかを取り除くと、ファイルはコンパイルできなくなります。

有効にする

{
    "compilerOptions": {
        "strict": true
    }
}

個々のフラグは、どちらの方向でも strict より優先されます。"strict": true, "strictNullChecks": false は null チェック以外をすべて有効にし、"strict": false, "noImplicitAny": true はそのひとつだけを有効にします。新しい strict 系のフラグはこのグループに加わるので、strict を使えば今後のリリースで追加されるチェックも有効になります。

TypeScriptの strict は、実行時のモードであるJavaScriptの "use strict" ディレクティブとは関係ありません。TypeScript 7 は必要な場所に常に "use strict" を出力し、alwaysStrict: false を設定するとエラー TS5108 になります(このオプションは削除されました)。

各フラグが検出するもの

フラグ報告する内容エラー
noImplicitAny型が気づかないうちに any になるパラメーターや変数TS7006 Parameter 'x' implicitly has an 'any' type.
strictNullChecksnull や undefined かもしれない値の使用TS18048 'u' is possibly 'undefined'.
strictFunctionTypesパラメーターの型が必要な型より狭い関数の代入TS2322
strictBindCallApply.call、.bind、.apply への誤った引数TS2345
strictPropertyInitialization一度も代入されないクラスのフィールドTS2564 Property 'name' has no initializer and is not definitely assigned in the constructor.
noImplicitThis入れ子の function の中などで暗黙の any 型になる thisTS2683
useUnknownInCatchVariables絞り込む前の catch 変数(型は unknown)の使用TS18046 'err' is of type 'unknown'.
strictBuiltinIteratorReturn組み込みのイテレーターの it.next().value を常に定義済みとして扱うことTS2322

いちばん多くのコードに影響するのは noImplicitAny と strictNullChecks の2つです。次のブロックはわざと両方に違反しています:

出力は index.ts(2,17): error TS7006: Parameter 'x' implicitly has an 'any' type. と index.ts(11,13): error TS18048: 'user' is possibly 'undefined'. です。strict がなければこれはコンパイルが通り、実行時に TypeError: Cannot read properties of undefined (reading 'name') でクラッシュします。strict があれば、そのクラッシュがコンパイルエラーになります。直し方はこのページの最初のブロックです。

strictFunctionTypes が存在する理由

文字列しか扱えない関数を、数値が来るかもしれない場所で使ってはいけません。次のチェックは @ts-expect-error で黙らせてあるので、実行してエラーが何を防いでいるかを確認できます:

コメントがなければ、この代入はエラー TS2322 Type '(s: string) => void' is not assignable to type 'Handler'. になり、続いて Types of parameters 's' and 'value' are incompatible. と表示されます。設計上の例外がひとつ残っています。メソッド構文で宣言したメソッド(インターフェースの中の handle(value: string | number): void)のパラメーターは今もゆるい方法でチェックされるので、そうしたメソッドには shout をエラーなしで代入できてしまいます。

strictPropertyInitialization

クラスのフィールドは、宣言かコンストラクターで必ず値を受け取らなければなりません。満たす方法は3つあります:

出力:

Account {
  owner: 'Ada',
  balance: 0,
  history: [],
  lastLogin: undefined,
  sessionId: 's-1'
}

target が ES2022 ではクラスのフィールドは本物のJavaScriptのフィールドなので、lastLogin と sessionId のプロパティは値 undefined で存在します。! はチェックを取り除くだけで実行時の保護は何も加えないので、ほかの書き方を優先しましょう。このフラグには strictNullChecks が必要で、それを無効にするとこちらも無効になります。

既存のプロジェクトで strict を有効にする

大きなコードベースを一度に strict に切り替えると、何百ものエラーが出ることがあります。strict は TypeScript 7 のデフォルトなので、tsconfig.json で一度も strict に触れていないプロジェクトをアップグレードすると、自動的に有効になります。移行中に以前の動作が必要なら "strict": false と書きます。ビルドを通したまま進める手順:

  1. "strict": true を追加し、エラーがいちばん多いフラグ(たいてい "strictNullChecks": false と "noImplicitAny": false)を無効にします。
  2. 残りのエラーを直したら、フラグをもうひとつ有効にして繰り返します。
  3. noImplicitAny の修正はほとんどがパラメーターの型注釈です。strictNullChecks では、値がないかもしれない場所に | undefined を追加し、?.、??、if のチェックで処理します。
  4. 修正を後回しにするしかない行には、理由を添えて // @ts-expect-error を書きます。@ts-ignore と違い、問題がなくなるとエラーを報告するので、リストは自然に減っていきます。

as any や ! でエラーをまとめて黙らせるのはやめましょう。どれも、そのフラグが見つけるために追加されたバグそのものを隠してしまいます。

strict に含まれない便利なフラグ

これらは、正しいことも多いコードを拒否するので別になっています。それでも多くのプロジェクトが有効にしています。

フラグ内容
noUncheckedIndexedAccessarr[i] と record[key] の型に undefined が含まれる
exactOptionalPropertyTypesdebug?: boolean はキーの省略は受け付けるが debug: undefined は受け付けない
noImplicitReturns戻り値のある関数のすべてのコードパスが return しなければならない(TS7030)
noImplicitOverride基底クラスのメソッドをオーバーライドするメソッドには override が必要(TS4114)
noFallthroughCasesInSwitch空でない case は break、return、throw で終わらなければならない(TS7029)
noUnusedLocals, noUnusedParameters使われていない変数とパラメーターがエラーになる
noPropertyAccessFromIndexSignatureインデックスシグネチャのキーには obj.key ではなく obj["key"] を使わなければならない

実際のバグをいちばん多く見つけるのは noUncheckedIndexedAccess です。有効にすると:

const scores = [90, 85];
const d: Record<string, number> = {};

const third: number = scores[2]; // error TS2322: Type 'number | undefined' is not assignable to type 'number'.
const c: number = d["x"];        // same error

const safe = scores[2] ?? 0;     // number
for (const s of scores) {        // for...of is not affected: s is number
    console.log(s);
}

TypeScript 7 の tsc --init は、生成する設定で strict と並んで noUncheckedIndexedAccess と exactOptionalPropertyTypes を有効にします。

よくある質問

TypeScriptの strict モードは何をしますか?

"strict": true は、より厳しい一連のチェックを有効にします: noImplicitAny、strictNullChecks、strictFunctionTypes、strictBindCallApply、strictPropertyInitialization、noImplicitThis、useUnknownInCatchVariables、strictBuiltinIteratorReturn。これらを合わせると、any が気づかないうちに紛れ込むのを防ぎ、null と undefined を型システムの一部にします。

TypeScriptの strict モードはデフォルトで有効ですか?

TypeScript 7 では有効です。strict のデフォルトは true なので、strict の設定がないプロジェクトではすべての strict チェックが有効になります。tsc --init も "strict": true を明示的に書き込みます。無効にするには "strict": false と書く必要があります。

strict のチェックのひとつだけを無効にして、残りを有効のままにできますか?

できます。個々のフラグは strict より優先されます: { "strict": true, "strictNullChecks": false } は、null チェック以外のすべての strict チェックを有効のままにします。大きなコードベースを1フラグずつ移行するときの一般的な方法です。

TypeScriptの strict モードはJavaScriptの "use strict" と同じですか?

違います。"use strict" はコードの動作を変えるJavaScriptの実行時のモードです。TypeScriptの strict は型チェッカーが報告する内容を変えるだけです。TypeScript 7 はモジュールでない出力には常に "use strict" を出力し、alwaysStrict: false は削除されたオプションです。

strict に noUncheckedIndexedAccess は含まれますか?

含まれません。noUncheckedIndexedAccess、exactOptionalPropertyTypes、noImplicitReturns、noImplicitOverride、noFallthroughCasesInSwitch は、自分で有効にする別のフラグです。tsc --init は生成する設定で最初の2つを有効にします。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める