ebisen blog.

TypeScriptのルールをstrictにしたときにつまずいたこと

eslinttypescript

eslintをstrictにした

このブログはTypeScriptで開発しています.型定義が弱いところがあり,eslintのルールを見直してみようと思ったのがきっかけ.一つ一つ検討していくのは骨が折れるので,一旦strict系のルールを有効にしようとなりました.

strictにするにはtsconfig.jsoncompilerOptionsstrictフラグをtrueにします.

// tsconfig.json
{
  "compilerOptions": {
    "strict": true
  }
}

この結果,めちゃくちゃeslintに怒られたので,その作業ログを残します.

strict-boolean-expressions

これは,booleanでない値を暗黙的にbooleanのように評価することを規制するルール.

例えばこんなコード.

const apple = {
  color?: string
}

// Unexpected nullable string value in conditional. Please handle the nullish/empty cases explicitly. if (apple.color) { // なんかの処理 }

appleオブジェクトのcolorプロパティはstring | undefinedという状況で,truthyのときだけなにかの処理をしたいという分岐を書いています.

これのなにが問題かというと,colorプロパティがundefinedや空文字のとき(つまりfalsyとのき)に暗黙的な型変換が行われ,ifブロックの中が評価されるということ.いつtrueとしたくて,いつfalseとしたいかをbooleanで明確に書きなさいというルールがstrict-boolean-expresiionsだと理解しています.

ではどう書けばいいかというと,次のような感じ.

const apple = {
  color?: string
}

if (apple.color !== undefined) { // なんかの処理 }

undefinedでないときのみ,ifブロックの中が評価されるという分岐にしました.これでエラーは消えます.空文字の場合もifブロック内を評価してほしいときは,さらに条件を追加する必要があります.

多少コード量が増えますが,型安全性は増しました.

参考:Falsy値を比較せずにそのまま判定に使うことはやめよう

補足:truthyfalsy

ちょっとここでtruthyfalsyについてまとめておきます.

falsyな値

  • string型の空文字''
  • number型の0
  • number型のマイナスゼロ-0
  • number型のNaN
  • bigint型の0n
  • boolean型のfalse
  • object型のdocument.all
  • null
  • undefined

参考:Falsy (偽値) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN

filtersort

文字列の配列からundefinedを取り除き,ソートしたいという処理でエラーがでました.

const array = ['hoge', undefined, 'fuga', undefined]

const newArray = array .filter((el) => el) // ここでundefinedを消したかった .sort((a, b) => a > b) // ここで降順に並べたかった

filterメソッドのコールバック関数の返り値はboolean

'hoge''fuga'truthyで,undefinedfalsyなので,これで行けると思いましたが,上のstrict-boolean-expressionで怒られました.

sortメソッドのコールバック関数の返り値はnumber

abundefinedのことがあるよ」と怒られました.一つ前のプロトタイプチェーンでfilterをしているので,undefinedはないはずなのに....また,「booleanであるa > bではなく,numberを返しなさい」と怒られました.

修正方法

以下のように修正しました.

const array = ['hoge', undefined, 'fuga', undefined]

const newArray = array .filter((el): el is string => typeof el === 'string') .sort((a,b) => b.localeCompare(a))

  • is演算子を使って,filterメソッド適用後はstring型のみになることを明示しました.
  • Stringオブジェクトの組み込みメソッドであるlocaleComparenumberを返すように変更しました.

その他の参考資料