😶‍🌫️

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 専用出入口のないカプセルホテル。

結論: 型の海を泳ぐなら浮輪 (=テスト) と酸素ボンベ (=ドキュメント) を忘れるな


1. the typeof サファリツアー

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 — 畑違いの合コンは禁止

5. document.all ― 幽霊より面倒な存在

HTML の亡霊 document.alltypeof 上は '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 の議事録を読むと眠れなくなる理由

  1. Stage 0: "思いついた!" — 朝礼での勢い。
  2. Stage 1: "仕様書いてみた!" — 妄想に図面が付く。
  3. Stage 2: "実装できそう!" — 机上の空論卒業。
  4. Stage 3: "ブラウザ入れた!" — 現場猫が『ヨシ!』。
  5. 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 で焚き火を囲もう。


脚注
  1. 観測した途端にバグ報告が爆増する。観測者効果を体験できるエンジニア向けホラーアトラクション。観測者が新人の場合、報告書の日本語もバグるため二重にスリリング。 ↩︎

  2. キーボード配列のせいにしてはいけないが、おそらくそう。なお当時の社内方針は「〆切が明日なら昨日完成したことにする」であり、安心と信頼の強行突破。 ↩︎

  3. ソースを辿ると コメント欄に埋まる泣き言 が化石化して発掘される。バージョン管理が CVS だったため、スコップよりも忍耐が必要。 ↩︎

  4. 2020 年、とある新人が上司の「1 行で直せ」を真に受けて 1 行コミット→本番サーバー沈没。以後、その会社では == を書くとき地雷マークをコメントで添える文化が誕生。 ↩︎

  5. "Object でよくね?" 派との宗教戦争が続く。双方とも最新ベンチマークより 2005 年のブログ記事を引用しがち。 ↩︎

  6. NaN に友情は通じるらしい。Set にとって最大の敵は重複よりも 自己肯定感。NaN は「俺は唯一無二」と主張して席を確保する。 ↩︎

  7. 数字も寝かせれば味が出る。20 年熟成の await 42 の香りは芳醇だが、朝イチのデプロイでフリーズドライになる運命。 ↩︎

  8. 「型体操で Health Care!」というスローガンを掲げるも、実際の運動量は any を握力で捻るリストカールのみ。 ↩︎

  9. 議事録は睡眠導入剤として高評価。ページ毎に羊 (Function.prototype) が 1 匹ずつ跳ねる。 ↩︎

  10. 焼き過ぎると黒焦げ (=パフォーマンス低下)。ただし表面だけ炙って液体窒素で急冷すると、CTO が「技術的負債アイスブレイク」と命名しがち。 ↩︎

Discussion