while(true)でESLintのno-constant-conditionが出たときの対処法

no-constant-conditionとは

no-constant-conditionは条件文で定数式を禁止するESLintのルールです。

例えば、if (false) や while (true) などを使用すると、no-constant-conditionのルールが有効だと警告が表示されます。

eslint:recommendedが有効だとno-constant-conditionのルールも適用されるので、対象の環境が多いルールです。

JavaScript
if (false) {
  doSomething()
}

while (true) {
  doSomething()
}

特に while (true) は無限ループの処理としてよく利用されるので、no-constant-conditionの警告が表示されやすいです。

no-constant-conditionの警告を消す方法

ESLintで表示されるno-constant-conditionの警告を部分的に消したい場合は、警告が表示される上に「/* eslint no-constant-condition: "off" */」のコメントを追加すれば消えます。

JavaScript
/* eslint no-constant-condition: "off" */
while (true) {
  doSomething()
}

.eslintrc.cjsなどの設定ファイルのrulesに「'no-constant-condition': 'off',」を追加しても消えますが、すべてのno-constant-conditionが無効化されるので避けたほうが良いです。

JavaScript
module.exports = {
  root: true,
  env: { browser: true, es2020: true },
  extends: [
    'eslint:recommended',
  ],
  rules: {
    'no-constant-condition': 'off',
  },
}

while (true) は極力避けたほうが良い

while (true) のような処理は極力避けたほうが良いです。

例えばテキストファイル内の特定の文字列(foo)がいくつあるかをカウントするような処理の場合、while (true) でインデックスの位置を加算していって全体を検索することがあります。

JavaScript
import { readFileSync } from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'

const filePath = fileURLToPath(import.meta.url)
const fileDir = path.dirname(filePath)
const dataFile = path.join(fileDir, 'data.txt')
const data = readFileSync(dataFile, { encoding: 'utf8' })
let count = 0
let currentIndex = 0

while (true) {
  const nextIndex = data.indexOf('foo', currentIndex)
  if (nextIndex >= 0) {
    count++
    currentIndex = nextIndex + 1
  } else {
    break
  }
}
console.log(count)

しかし、while (true) 部分はwhile (currentIndex < data.length) のように書き換えれば、no-constant-conditionの警告が表示されなくなります。

JavaScript
import { readFileSync } from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'

const filePath = fileURLToPath(import.meta.url)
const fileDir = path.dirname(filePath)
const dataFile = path.join(fileDir, 'data.txt')
const data = readFileSync(dataFile, { encoding: 'utf8' })
let count = 0
let currentIndex = 0

while (currentIndex < data.length) {
  const nextIndex = data.indexOf('foo', currentIndex)
  if (nextIndex >= 0) {
    count++
    currentIndex = nextIndex + 1
  } else {
    break
  }
}
console.log(count)

また、以下のようにPromiseを使用すると、while内を毎秒計5回処理させることもできます。

JavaScript
let count = 0

while (count < 5) {
  console.log(count)
  count++
  await new Promise((resolve) => setTimeout(resolve, 1000))
}

while (true) を使用する際はno-constant-conditionのルールに引っかからずに処理を書けないか、検討したほうが良いでしょう。