JavaScriptの奇妙な型を巡る旅
― typeof null === "object"
に乾杯―
JavaScript の型システムはシュレディンガーの猫より多忙である[1]。箱を開けても閉めても、とりあえず鳴き声だけは聞こえる。
0. TL;DR を TL;DR と呼べない長さで
-
typeof null
が'object'
: 1995 年のタイポが 30 年寝かされワイン化[2]。 -
NaN !== NaN
: 自己否定を習得した数値。哲学科卒の数学者が泣いた。 -
[] + {}
と{} + []
は真逆の結果。演算子より先に人生を見直そう。 -
0 == "0"
だが0 === "0"
ではない。ダイエット前後の自画像の差分。 -
typeof function(){}
が'function'
なのにclass A {}
も'function'
。役職が増えても名刺は白紙。 -
Symbol()
はプリミティブなのにnew Symbol()
は TypeError。VIP 専用出入口のないカプセルホテル。
結論: 型の海を泳ぐなら浮輪 (=テスト) と酸素ボンベ (=ドキュメント) を忘れるな。
typeof
サファリツアー
1. the 1.1 null ― いなかっ た ことにされるオブジェクト
null
は「何もない」を表すプリミティブ……のはずが typeof
すると object
。初代実装時のバグ[3] が、永久凍土みたいにコールドスリープ中。
typeof null; // "object" (Yes, still in 2025)
1.2 undefined ― 教壇に立つホームレス
undefined
は「宣言したけど値が入っていない箱」。typeof undefined
は 'undefined'
で平和に見える。しかし void 0
という裏口もある。玄関が複数ある家は大抵コメディ用セット。
1.3 NaN ― 形而上学的数値
NaN
は "Not a Number" なのに数値型。でも自分と等しくない。大学の同期会に来て「誰お前?」と言われるあの感じ。
NaN === NaN; // false
Number.isNaN(NaN); // true — 本名で呼んであげよう
2. 比較演算子の昼と夜 — 机上の空論を実装で証明
- ゆるふわ変換 (==): "とりあえず通してみよう" 精神。
- スパルタ厳密 (===): "紙の裏表まで確認" 精神。
-
null == undefined // true
: 空っぽ同士は意気投合。 -
false == 0 // true
なのにfalse == "0" // true
。二股どころか三股。 -
[] == ![] // true
: 志村うしろー!級のどんでん返し[4]。
"== を使うときは家族の同意書をもらおう" — 匿名のコードレビューより
3. コレクション三国志: Array, Object, Map, Set (ついでに Weak*)
-
Array: 整列を強いられるのに
typeof []
は'object'
。体育会系クラブ所属の事務員。 - Object: 万能雑貨箱。ただし鍵は文字列。セキュリティ? 気合いです。
- Map: 2015 年に登場した正統後継。祖父 (Object) の遺産相続がこじれて普及率はいまひとつ[5]。
-
Set: 値の重複 NG のはずが
NaN
は何個でも入るブラザーズシップ[6]。 - WeakMap / WeakSet: "寿命が尽きると消える" が売り文句。人間社会にも導入してほしい。
4. BigInt と 9007199254740991 の壁
JavaScript が安全に表せる最大整数 2^53 - 1
を超えると 暗算と運ゲーのハイブリッド になる。そこで登場した BigInt。だが BigInt(1) + 1
は投獄 (TypeError)。型は大事、特に新入りとは距離感を測ろう。
123n + 456n; // 579n — BigInt どうしは平和
123n + 456; // TypeError — 畑違いの合コンは禁止
document.all
― 幽霊より面倒な存在
5. HTML の亡霊 document.all
は typeof
上は 'undefined'
なのに truthy。心霊写真か?
typeof document.all === "undefined"; // true
Boolean(document.all); // true
存在しないことになっているのに存在している。量子重ね合わせをブラウザが先取り。
6. Promise — 型より先に希望を返す
Promise
は非同期を包む箱。が、中身が来なければただの空箱。typeof
すると 'object'
なのに .then
を持つ新興宗教の壺。
const p = Promise.resolve(42);
typeof p; // "object"
さらに await 123
が許可された結果、数値までもが Promise ごっこに参加。もう誰でもアイドル時代[7].
7. 型の楽園? — TypeScript の甘い罠
TypeScript は静的型という名の P2P 保証人[8]。だが any
を 1 行混ぜた瞬間、保証人は夜逃げする。
type Fruit = "apple" | "banana";
let f: Fruit = JSON.parse("\"dragonfruit\""); // compile passes, runtime cries
unknown
? それは「まず調べろ」という宿題を投げてくる教師。逃げたら単位を落とす。
8. TC39 の議事録を読むと眠れなくなる理由
- Stage 0: "思いついた!" — 朝礼での勢い。
- Stage 1: "仕様書いてみた!" — 妄想に図面が付く。
- Stage 2: "実装できそう!" — 机上の空論卒業。
- Stage 3: "ブラウザ入れた!" — 現場猫が『ヨシ!』。
- Stage 4: "みんな使ってる!" — Stack Overflow が炎上。
Stage 4 に到達する頃には、あなたの古いスマホが化石になっている[9]。
9. 未来予想図
-
typeof null
が'null'
へ修正 → 全世界の if 文が逆立ち。Stack Overflow の PV が増加し広告収入が急騰。 -
==
が非推奨に → npm のダウンロード数より警告行数が多くなる。 -
AI 型推論 → 結果として全て
unknown
、それをコンパイラが怒り、開発者が泣く。 -
void
演算子が流行 → ES2028: スマホに「ボタンを押すと何もしない」アプリが標準搭載。
10. おわりに
JavaScript の型は マシュマロのように柔らかい。焼けばどこまでも伸び、冷やせば意外と硬い。つまり、扱いはあなた次第[10]。
"最強のデバッグツールは console.log と 好奇心" — あるベテランの名言
それでは npm run ambiguity
を実行し、ブラウザの DevTools で焚き火を囲もう。
-
観測した途端にバグ報告が爆増する。観測者効果を体験できるエンジニア向けホラーアトラクション。観測者が新人の場合、報告書の日本語もバグるため二重にスリリング。 ↩︎
-
キーボード配列のせいにしてはいけないが、おそらくそう。なお当時の社内方針は「〆切が明日なら昨日完成したことにする」であり、安心と信頼の強行突破。 ↩︎
-
ソースを辿ると コメント欄に埋まる泣き言 が化石化して発掘される。バージョン管理が CVS だったため、スコップよりも忍耐が必要。 ↩︎
-
2020 年、とある新人が上司の「1 行で直せ」を真に受けて 1 行コミット→本番サーバー沈没。以後、その会社では
==
を書くとき地雷マークをコメントで添える文化が誕生。 ↩︎ -
"Object でよくね?" 派との宗教戦争が続く。双方とも最新ベンチマークより 2005 年のブログ記事を引用しがち。 ↩︎
-
NaN に友情は通じるらしい。
Set
にとって最大の敵は重複よりも 自己肯定感。NaN は「俺は唯一無二」と主張して席を確保する。 ↩︎ -
数字も寝かせれば味が出る。20 年熟成の
await 42
の香りは芳醇だが、朝イチのデプロイでフリーズドライになる運命。 ↩︎ -
「型体操で Health Care!」というスローガンを掲げるも、実際の運動量は
any
を握力で捻るリストカールのみ。 ↩︎ -
議事録は睡眠導入剤として高評価。ページ毎に羊 (Function.prototype) が 1 匹ずつ跳ねる。 ↩︎
-
焼き過ぎると黒焦げ (=パフォーマンス低下)。ただし表面だけ炙って液体窒素で急冷すると、CTO が「技術的負債アイスブレイク」と命名しがち。 ↩︎
Discussion