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 )); ^
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 )); ^
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 )); ^
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 )); ^
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 )); ^
typeofチェックはnullでも真になるため、その後のプロパティアクセスでエラーになります。
直し方: null を { cost: 100 } にします。
よくある誤解
「typeofで'object'と判定できればプロパティを読んでも安全」ではありません。nullも同じ判定を通過するため、その後のプロパティアクセスでエラーになります。
実務での勘所
この挙動は1995年の初期実装に由来する有名なバグです。当時のJavaScriptエンジンは値の型をビットの組み合わせ(型タグ)で表現しており、オブジェクトの型タグはたまたま000、nullは全ビットが0のヌルポインタとして表現されていました。typeofはこの型タグを見て判定するため、nullも「タグが000だからオブジェクト」と誤判定してしまったのです。TC39(JavaScript仕様の標準化団体)はこれを修正する提案を一度検討しましたが、すでに世界中のコードがこの挙動に依存しているため「ウェブを壊さない」という原則のもと修正を見送り、今も仕様上の既知の欠陥として残っています。