ESLintのno-unsafe-negationルールを徹底解説!読みやすく安全なコードを書くためのヒント


ESLint の "no-unsafe-negation" ルールは、関係演算子の左側を否定することを禁止します。

目的

このルールの目的は、以下の2つの問題を防ぐことです。

  1. 意図しないコード動作 関係演算子の左側を否定すると、意図しないコード動作が発生する可能性があります。 例:

    if (!key in object) {
        // ...
    }
    

    このコードは、keyobject に存在しないかどうかを検査する意図ですが、実際には keyfalse かどうかを検査しています。

  2. コードの読みやすさの低下 関係演算子の左側を否定すると、コードが読みづらくなります。 例:

    if (!(age >= 18)) {
        // ...
    }
    

    このコードは、age が 18 歳以上かどうかを検査する意図ですが、age が 18 歳未満かどうかを検査しているように読めてしまいます。

例外

このルールは、以下の場合は関係演算子の左側を否定することを許可しています。

  • instanceof 演算子 を使用している場合 例:

    if (object instanceof Array) {
        // ...
    }
    
  • 比較演算子 (==, !=)` を使用している場合 例:

    if (value != 0) {
        // ...
    }
    
  • 論理否定演算子 (not)` を使用している場合 例:

    if (key !== null) {
        // ...
    }
    

設定

このルールは、以下のオプションで設定できます。

  • "off": ルールを無効にします。
  • "warn": 違反を警告として報告します。
  • "error": 違反をエラーとして報告します。(デフォルト)

enforceForOrderingRelations オプション

このオプションは、**順序関係演算子 (<, >, <=, >=)` の左側を否定することを許可するかどうかに影響します。

  • true: 順序関係演算子の左側を否定することを禁止します。
  • false (デフォルト): 順序関係演算子の左側を否定することを許可します。

以下の例は、"enforceForOrderingRelations": true オプションを設定した場合のコードを示しています。

/*eslint no-unsafe-negation: ["error", { "enforceForOrderingRelations": true }] */

if (!(age >= 18)) {
  // ...
}

ESLint の "no-unsafe-negation" ルールは、関係演算子の左側を否定することを禁止することで、意図しないコード動作を防ぎ、コードの読みやすさを向上させることができます。



問題のあるコード

// 関係演算子の左側を否定している
if (!key in object) {
  // ...
}

if (!(age >= 18)) {
  // ...
}

if (value != 0) {
  // ...
}

if (object instanceof Array) {
  // ...
}

// 順序関係演算子の左側を否定している (enforceForOrderingRelations: true の場合)
if (!(age >= 18)) {
  // ...
}

以下のコードは、 "no-unsafe-negation" ルールによって違反が発生しないように修正されています。

// 論理否定演算子を使用する
if (object[key] === undefined) {
  // ...
}

// age >= 18 を直接比較する
if (age < 18) {
  // ...
}

// 厳格な等価比較を使用する
if (value !== 0) {
  // ...
}

// instanceof 演算子を使用する
if (Array.isArray(object)) {
  // ...
}

// 順序関係演算子の右側を否定する (enforceForOrderingRelations: true の場合)
if (age < 18) {
  // ...
}

このルールは、様々な種類の関係演算子に適用されます。

以下に、いくつかの例を示します。

等価演算子

// 問題のあるコード
if (!a == b) {
  // ...
}

// 修正コード
if (a !== b) {
  // ...
}

非等価演算子

// 問題のあるコード
if (!(a != b)) {
  // ...
}

// 修正コード
if (a === b) {
  // ...
}

大小比較演算子

// 問題のあるコード
if (!(a < b)) {
  // ...
}

// 修正コード
if (a >= b) {
  // ...
}

大小等価演算子

// 問題のあるコード
if (!(a <= b)) {
  // ...
}

// 修正コード
if (a > b) {
  // ...
}

これらの例は、 "no-unsafe-negation" ルールがどのように動作するかを理解するのに役立ちます。



しかし、このルールは、場合によっては意図した動作を妨げることもあります。

そのような場合は、以下の代替方法を検討することができます。

論理否定演算子 (not) を使用する

関係演算子の左側を否定する代わりに、論理否定演算子 (not) を使用することができます。

例:

// 問題のあるコード
if (!key in object) {
  // ...
}

// 代替コード
if (!(key in object)) {
  // ...
}

比較演算子の右側を否定する

関係演算子の左側を否定する代わりに、比較演算子の右側を否定することができます。

// 問題のあるコード
if (!(age >= 18)) {
  // ...
}

// 代替コード
if (age < 18) {
  // ...
}

明示的な型変換を行う

関係演算子の左側を boolean 型に変換してから比較することができます。

// 問題のあるコード
if (!key in object) {
  // ...
}

// 代替コード
if (Boolean(key in object)) {
  // ...
}

ルールを無効にする

どうしても "no-unsafe-negation" ルールが意図した動作を妨げる場合は、ルールを無効にすることができます。

ただし、ルールを無効にする場合は、コードレビューなどで意図しないコード動作が発生していないことを確認する必要があります。

/*eslint no-unsafe-negation: "off" */
if (!key in object) {
  // ...
}

注意点

上記の代替方法は、いずれも状況によっては意図した動作と異なる結果になる可能性があります。

代替方法を使用する場合は、十分に注意する必要があります。

"no-unsafe-negation" ルールは、有用なルールですが、万能ではありません。

ルールが意図した動作を妨げる場合は、上記の代替方法を検討することができます。