【TypeScript】有効にすべきオプションまとめ

こんにちは、フリーランスエンジニアの太田雅昭です。

TypeScriptのオプション

TypeScriptでは、tsconfig.jsonで様々なオプションを指定できます。中には互換性を重視して、デフォルトでは無効になっているものの、有効にすべきものもあります。今回は、そうした有効にすべきオプションです。

noImplicit系

noImplicit系は下記があります。

  • noImplicitAny
  • noImplicitReturns
  • noImplicitThis
  • noImplicitOverride

暗黙の定義を許可しないようにできます。基本的に、noImplicit系はすべてtrueにするのが良いかと思います。

noImplicitAny

noImplicitAnyは、暗黙anyを許可しないようにします。strict: trueで自動的にtrueになります。逆に言えば、strict: trueでも、noImplicitAnyがfalseの場合は動作しません。

下記はxが暗黙anyで危険なため、検出されます。

function f(x) {
  console.log(x.trim());
}

noImplicitReturns

関数内の条件分岐で、すべてのパターンで値を返しているかがチェックされます(厳密には意味合いは違うかもしれませんが)。

例えば以下のようなコードの場合

function f(n: number) {
  if (n === 1) return 'a';
}

すべてのパターンでstringを返すのが、よくある実装かと思います。しかしn===1しか実装されていません。noImplicitReturns: trueの場合、こうしたケアレスミスを検出してくれます。

noImplicitThis

暗黙thisを検出してくれます。最近ではthisを使う機会が少なくなってきている(関数型への移行など)ので、あまり恩恵はないかもしれませんが、とりあえずtrueにしておくと良さそうです。バインド忘れなどは、ふとした時に起きそうですので、そうした場合に安心です。

noImplicitOverride

クラスでの暗黙overrideを検出してくれます。overrideかどうかをはっきりさせることで、基底クラスの変更に伴う予期せぬバグなどの防止につながります。

その他の重要なオプション

noUncheckedIndexedAccess

noUncheckedIndexedAccessは、配列やオブジェクトでundefinedの可能性を入れるかどうかを指定します。これはぜひtrueにすべきプロパティです。

noUncheckedIndexedAccess: falseの場合、

const strings = ['a', 'b', 'c'];
const s = strings[5]; // sは string になる
console.log(s.trim()); // 通ってしまう

const obj = { a: 1, b: 2, c: 3 } as Record<string, number>;
const value = obj['d']; // valueは number になる
console.log(value.toFixed(2)); // 通ってしまう

このように、何でもかんでもあたいが存在する扱いとなってしまいます。これでは事前にエラーを検出することが難しくなります。

そのため、noUncheckedIndexedAccessをtrueにします。するとundefinedとのユニオンタイプとなり、エラーを検出できます。

const strings = ['a', 'b', 'c'];
const s = strings[5]; // sは string | undefined になる
console.log(s.trim()); // エラーになる

const obj = { a: 1, b: 2, c: 3 } as Record<string, number>;
const value = obj['d']; // valueは number | undefined になる
console.log(value.toFixed(2)); // エラーになる

noFallthroughCasesInSwitch

noFallthroughCasesInSwitchは、switch構文のケアレスミスをチェックしてくれます。具体的には、break無しを許容しないようになります。

下記のような、危ういコードも検出してくれるようになります。

let n = 0;
switch (n) {
  case 0:
    console.log(0);
  case 1:
    console.log(1);
}

n===0の場合、0を出力した後に1も出力されてしまいます。こうしたケアレスミスが炙り出されます。

まとめ

今回あげたオプションは以下となります。

{
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
}

これを常に入れておくと、よりTypeScriptの恩恵が受けられるかと思います。