Kodokon kodokon.com

厳格な tsconfig: 重要なオプションとよくあるエラー

strict モードが実際に何を有効にするのかを理解し、既存プロジェクトでそれが明らかにする典型的なエラーへの対処方法を知ります。

11 分 · 3 問

このレッスンを Kodokon で開く

"strict": true はひとつのオプションではなく、一群のチェックを有効にする 集合体 です。strictNullChecksnoImplicitAnystrictFunctionTypesstrictBindCallApplystrictPropertyInitializationnoImplicitThisuseUnknownInCatchVariablesalwaysStrict が含まれます。TypeScript の新しいバージョンごとにさらに追加される可能性があります。strict を有効にすることは、将来のチェックを購読することです。各フラグは個別に無効化することもでき、既存のコードベースでの段階的な移行を可能にします。

JSON
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true,
    "verbatimModuleSyntax": true,
    "skipLibCheck": true
  }
}
集合体の外にあるオプションで拡張された厳格なベースライン(JSON ファイル)。

最も影響の大きい 2 つのフラグは strictNullChecksnoImplicitAny です。前者はすべての型から nullundefined を取り除きます。潜在的に存在しない値はすべて T | undefined と宣言し、使用前に処理しなければなりません。後者は、注釈のない引数が any にフォールバックすることを拒否します。この 2 つが揃うと、JavaScript の大きなバグ 2 系統を排除できます。「cannot read property of undefined」と、チェックされない値の伝播です。useUnknownInCatchVariables が絵を完成させます。JavaScript は何でも throw できるため、catch の変数は unknown になります。

TYPESCRIPT
function findPort(
  env: Record<string, string | undefined>
): number {
  const raw = env["PORT"];
  if (raw === undefined) {
    return 3000;
  }
  return Number.parseInt(raw, 10);
}

declare function riskyOperation(): void;

try {
  riskyOperation();
} catch (err) {
  const message =
    err instanceof Error ? err.message : String(err);
  console.error(message);
}
2 つの厳格なパターン。不在の処理と、unknown としての catch。

よくある移行時のエラーと、その本当の対処法です。「Object is possibly undefined」には、非 null アサーション !(クラッシュを別の場所に移すだけ)よりも、絞り込み(if)、オプショナルチェーン ?.?? のデフォルトを優先しましょう。「Property has no initializer」(strictPropertyInitialization)には、フィールドに ! を付けるのではなく、コンストラクタで初期化しましょう。??|| の落とし穴にも注意してください。port || 30000"" も置き換えますが、port ?? 3000nullundefined だけを置き換えます。

TYPESCRIPT
interface Settings { retries?: number }

function resolveRetries(s: Settings): number {
  const bad = s.retries || 3;
  const good = s.retries ?? 3;
  return good;
}

const names = ["Ada", "Linus"];
const first = names[0];
const upper = first?.toUpperCase() ?? "N/A";
retries: 0 では bad = 3 だが good = 0。インデックスアクセスは次にチェックされます。

集合体の外にも、チームでの議論に値する 3 つのオプションがあります。noUncheckedIndexedAccess はすべてのインデックスアクセス(arr[i]dict[key])に undefined を追加します。より安全ですが、配列操作のコードでは冗長になります。多くのチームは新規プロジェクトでのみ採用します。exactOptionalPropertyTypes は「プロパティが不在」と「プロパティが undefined に設定」を区別し、パッチにとって重要です。skipLibCheck は依存関係の .d.ts ファイルのチェックをスキップします。ビルド時間と、ライブラリ間の衝突検出との間の意図的なトレードオフです。

理解度チェック

このレッスンの要点をしっかり覚えているか確認しましょう。

  1. tsconfig.json の "strict": true は正確には何をしますか?
    • strictNullChecks オプションだけを有効にする
    • 一群の厳格なフラグを有効にし、それぞれは個別に無効化できる
    • any 型の使用を、明示的なものであっても禁止する
    • ES5 モードでのコンパイルを強制する
  2. retries?: number を 0 に設定した場合、retries || 3retries ?? 3 の違いは何ですか?
    • 違いはない。どちらも 0 を返す
    • || は 0 が falsy なので 3 を返す。?? は null と undefined だけを置き換えるので 0 を返す
    • ?? は 0 を不在として扱うので 3 を返す
  3. 型付けの負債を印付けするのに、// @ts-ignore よりも // @ts-expect-error を優先するのはなぜですか?
    • @ts-expect-error は複数のエラーを一度に抑制する
    • @ts-ignore は strict モードで動作しない
    • @ts-expect-error は問題が解決されるとエラーになるため、負債が自己浄化される