JavaScriptのESLintは問題を検出しにくいので注意が必要

ESLintだけを使ってはいけない

JavaScriptのLintツールといえば、ESLintが標準のように使われているケースが多いです。

しかし、最近はOxcやBiomeのような新しいツールが存在しているので、ESLintの問題点が指摘されることが増えています。

特に指摘されるのが 「問題を検出しにくい」 という点です。

ESLintは2013年に登場したツール

ESLintは2013年に登場しました。

当時は

  • Node.jsもまだ発展途上
  • TypeScriptもほぼ普及していない
  • JavaScriptの仕様も現在よりかなり少ない

という時代でした。

つまり、現在のJavaScript環境とは前提が大きく違います。

JavaScriptとして合法なら警告しない設計

ESLintは基本的にJavaScriptとして合法なら禁止しないという設計思想があります。

例えば次のコードです。

これは配列の要素を削除しているように見えますが、実際には配列にemptyを作るだけです。

JavaScript
const arr = [1, 2, 3]
delete arr[0]
console.log(arr)
// [empty, 2, 3]

しかし、ESLintにはこのコードを禁止するルールがありません。

deleteで配列を削除した際の3つの大きな問題点

1. lengthでのカウントがおかしくなる

deleteは要素の削除ではなくemptyになるだけなので、lengthでカウントした際に元のlengthのままになります。

JavaScript
const arr = [1, 2, 3]
console.log(arr.length) // 3 
delete arr[0]
console.log(arr)
// [empty, 2, 3]
console.log(arr.length) // 3

2. 配列メソッドの動きがバラバラになる

deleteで配列をemptyにすると配列メソッドの動きがバラバラです。

例えば、forEachの場合はemptyを無視するため以下の結果になります。

JavaScript
const arr = [1, 2, 3]
const result = []
delete arr[0]
arr.forEach((v) => result.push(v * 2))
console.log(result)
// [4, 6]

mapの場合はemptyを無視しないため、emptyを残したままの結果となります。

JavaScript
const arr = [1, 2, 3]
delete arr[0]
const result = arr.map((v) => v * 2)
console.log(result)
// [empty, 4, 6]

このようなメソッドの動きの違いはバグの温床になります。

3. パフォーマンスが悪化する

JavaScriptエンジンは「連続した配列(packed array)」と「emptyを含む配列(sparse array)」で処理を変えています。

「emptyを含む配列(sparse array)」で処理した場合は通常よりも処理に時間がかかるため、パフォーマンスが悪化します。

配列の削除はspliceまたはtoSplicedを使用する

要素を削除する際はspliceまたはtoSplicedを使用します。

JavaScript
const arr = [1, 2, 3]
arr.splice(0, 1)
console.log(arr)
// [2, 3]

const arr2 = [1, 2, 3]
arr2.splice(1, 1)
console.log(arr2)
// [1, 3]

const arr3 = [1, 2, 3]
arr3.splice(1, 2)
console.log(arr3)
// [1]

他の変数に代入するときはtoSplicedを使用します。

toSplicedを使用すれば元の配列は変更されないので、代入する際は必ずこちらを使用してください。

JavaScript
const arr = [1, 2, 3]
const newArr = arr.toSpliced(0, 1)
console.log(arr)
// [1, 2, 3]
console.log(newArr)
// [2, 3]

spliceは破壊的なので、特に理由がなければ非破壊(元の配列が変更されない)toSplicedを使用したほうが良いです。

非破壊にしたほうがReactなどの状態管理との相性も良く、バグが発生する可能性が低くなります。

他のLinterでは配列へのdeleteを禁止にできる

OxcやBiomeなどの最近のLinterにはno-array-deleteというルールがあり、配列へのdeleteを禁止できます。

また、typescript-eslintにもno-array-deleteのルールがあるので、OxcやBiomeに変更できない場合は、こちらを追加するという手もあります。

https://typescript-eslint.io/rules/no-array-delete