Code Fix

中級

typeof null === 'object' の罠

typeof演算子はnullに対して"object"を返します。これは言語仕様初期からのバグ扱いの挙動で、修正すると既存コードが壊れるため現在も残っています。オブジェクトかどうかの判定にtypeofだけを使うとnullをすり抜けさせてしまいます。

エラーメッセージの読み方

main.js:3
main.js
ファイル名
3
行番号 — 実際にクラッシュした行
TypeError
例外クラス — 何が起きたか。ここを検索するのが最短です
Cannot read properties of null (reading 'label')
内容 — 期待していたもの、または受け付けられなかったもの

このエラーが出る典型パターン

パターン1

 1  function describe(value) {
 2    if (typeof value === "object") {
 3      return value.label;
 4    }
 5    return "primitive";
 6  }
 7  console.log(describe(null            ));
                                 ^
main.js:3 return value.label; ^ TypeError: Cannot read properties of null (reading 'label')

typeof nullは"object"を返すため、null対策のつもりのtypeofチェックをすり抜けてしまいます。言語仕様初期からのバグ扱いの挙動で、今も修正されていません。

直し方: null を { label: "box" } にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  function area(shape) {
 2    if (typeof shape === "object") {
 3      return shape.width * shape.height;
 4    }
 5    return 0;
 6  }
 7  console.log(area(null                   ));
                                ^
main.js:3 return shape.width * shape.height; ^ TypeError: Cannot read properties of null (reading 'width')

typeof shape === "object"はnullでも真になるため、その後のプロパティアクセスでエラーになります。nullかどうかは別途チェックする必要があります。

直し方: null を { width: 4, height: 5 } にします。

この問題を解いてみる →

パターン3

 1  function describeUser(user) {
 2    if (typeof user === "object") {
 3      return user.name.toUpperCase();
 4    }
 5    return "unknown";
 6  }
 7  console.log(describeUser(null          ));
                                    ^
main.js:3 return user.name.toUpperCase(); ^ TypeError: Cannot read properties of null (reading 'name')

userがnullでもtypeofチェックは通過してしまい、name.toUpperCase()の手前で例外になります。

直し方: null を { name: "al" } にします。

この問題を解いてみる →

パターン4

 1  function summarize(item) {
 2    if (typeof item === "object") {
 3      return item.title.length;
 4    }
 5    return -1;
 6  }
 7  console.log(summarize(null            ));
                                  ^
main.js:3 return item.title.length; ^ TypeError: Cannot read properties of null (reading 'title')

typeof null は "object" になるため、nullを弾いたつもりの分岐を通過してしまいます。

直し方: null を { title: "box" } にします。

この問題を解いてみる →

パターン5

 1  function price(product) {
 2    if (typeof product === "object") {
 3      return product.cost * 1.1;
 4    }
 5    return 0;
 6  }
 7  console.log(price(null         ));
                            ^
main.js:3 return product.cost * 1.1; ^ TypeError: Cannot read properties of null (reading 'cost')

typeofチェックはnullでも真になるため、その後のプロパティアクセスでエラーになります。

直し方: null を { cost: 100 } にします。

この問題を解いてみる →

よくある誤解

「typeofで'object'と判定できればプロパティを読んでも安全」ではありません。nullも同じ判定を通過するため、その後のプロパティアクセスでエラーになります。

実務での勘所

この挙動は1995年の初期実装に由来する有名なバグです。当時のJavaScriptエンジンは値の型をビットの組み合わせ(型タグ)で表現しており、オブジェクトの型タグはたまたま000、nullは全ビットが0のヌルポインタとして表現されていました。typeofはこの型タグを見て判定するため、nullも「タグが000だからオブジェクト」と誤判定してしまったのです。TC39(JavaScript仕様の標準化団体)はこれを修正する提案を一度検討しましたが、すでに世界中のコードがこの挙動に依存しているため「ウェブを壊さない」という原則のもと修正を見送り、今も仕様上の既知の欠陥として残っています。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)