3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「==は使うな」の唯一の例外。x == null だけは使っていい理由

3
Posted at

「== は使うな、必ず === を使え」はほぼ正しいルールです。ただし例外が1つだけあり、それが x == null です。これだけは使ってよい、というのが本記事の主張です。

以前書いた || と ?? の記事(falsy全般とnull/undefinedの違い)、typeof null の記事(null判定にtypeofを使うと事故る話)とは別の切り口で、今回は「null と undefined を1回で判定する書き方として == null を採用してよいか」を扱います。

検証環境は Node.js v24.14.1 です。表示している出力はすべて実際に実行した結果です。

x == null の判定結果を実測する

const values = [
  ['null', null], ['undefined', undefined], ['0', 0], ["''", ''],
  ['false', false], ['NaN', NaN], ['[]', []], ['{}', {}], ["'0'", '0']
];
for (const [label, v] of values) {
  console.log(label.padEnd(10), 'x == null:', String(v == null).padEnd(5),
    '| ===null||===undefined:', String(v === null || v === undefined).padEnd(5),
    '| !x:', !v);
}
null       x == null: true  | ===null||===undefined: true  | !x: true
undefined  x == null: true  | ===null||===undefined: true  | !x: true
0          x == null: false | ===null||===undefined: false | !x: true
''         x == null: false | ===null||===undefined: false | !x: true
false      x == null: false | ===null||===undefined: false | !x: true
NaN        x == null: false | ===null||===undefined: false | !x: true
[]         x == null: false | ===null||===undefined: false | !x: false
{}         x == null: false | ===null||===undefined: false | !x: false
'0'        x == null: false | ===null||===undefined: false | !x: false

x == null が true になるのは null と undefined だけで、x === null || x === undefined と全行一致します。一方 !x は 0 '' false NaN まで true にする(falsyの罠)。== が危険なのは型変換が複雑だからですが、== null が true になる相手は null と undefined の2つだけで、0 や '' との間では型変換が起きません。

?? との使い分け

== null は「判定」、?? は「デフォルト値の代入」で役割が違います(?? と || の違いは上の過去記事で詳しく書きました)。

値を置き換えたいなら ??、null/undefined のときに早期リターンや分岐をしたいなら == null が読みやすい、という整理です。

function greet(name) {
  if (name == null) return 'guest';
  return name;
}
console.log(greet(null), greet(undefined), JSON.stringify(greet('')), greet('Taro'));
// guest guest "" Taro

空文字は通り、null/undefined だけがguestに倒れます。!name で書くと空文字もguest扱いになります。

ESLintの eqeqeq で例外を許可する

eqeqeq をそのまま有効にすると == null もエラーになります。ESLintのオプションで null だけ無視できます。

// eslint.config.mjs
export default [{
  rules: { eqeqeq: ["error", "always", { null: "ignore" }] }
}];

ESLint 9.39.5 で次のコードを検査しました。

const a = 1; const b = null;
console.log(a == b);     // 2行目
console.log(a == 2);     // 3行目
console.log(a == null);  // 4行目
  2:15  error  Expected '===' and instead saw '=='  eqeqeq
  3:15  error  Expected '===' and instead saw '=='  eqeqeq
✖ 2 problems (2 errors, 0 warnings)

2行目(変数どうしの ==)と3行目(数値との ==)はエラーで、4行目の == null だけが通ります。なお ESLint 公式ドキュメントによると、"smart" という別オプションもあり、リテラル同士の比較・typeof の比較・null との比較を許可します。「null だけ」に絞るなら上の書き方です。

typeof x == 'string' も両辺が文字列なので安全ですが、=== に変えても失うものがありません。== null は1回の比較で null と undefined の両方を拾えるという === にはない利点があるので、例外として残す価値があるのはこれだけ、というのが本記事の立場です。

どれを使うか

  • チームが「== 禁止」なら、無理に例外を作らず x === null || x === undefined でも構いません
  • TypeScript の strictNullChecks が有効な環境では、型が string | null | undefined のような値に対して x == null で null | undefined とそれ以外に絞り込まれます(型の絞り込み=narrowing)
  • 「値を置き換えたい」なら ??、「falsyを弾きたい(0や空文字も無効)」と本当に決めているときだけ !x

AIが書いたコードで == null を見かけたら

Claude Code などのAIが書いたコードに == null が混ざっていることがあります。機械的に === に直すと、null と undefined の両方を見る意図が片方だけになるバグを生むことがあります。

レビューでは、次の2点を見れば十分です。

  1. 比較相手が本当に null リテラルか(変数との == は別問題)
  2. null と undefined を同じ扱いにしたい意図があるか

== null を「意図のある慣用句」と読めれば、AIの出力を根拠を持って承認・修正できます。ルールは理由まで知って初めて、例外も判断できます。


未経験者向けの講座を運営しています

未経験から Next.js + Supabase + Claude Code で Webアプリを公開するまで を、全24セッションで体系化した教材です。Claude Code を学習パートナーにする CLAUDE.md と学習モード(learner / developer)の設計までセットで含みます。

※ Qiita 読者の方には易しすぎる内容なので、初心者の知り合いへの紹介や社内研修の参考としてどうぞ。

3
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?