【実務・中級編】 Promiseオブジェクトの型判定 – JavaScript実践ガイド

「Promiseか、それともただの偽物か?」――現場で泣きを見ないための型判定の深淵

フロントエンドの現場で、APIレスポンスや非同期処理を扱う際、「これって本当にPromiseだよな?」と疑心暗鬼になったことはないだろうか。

JavaScriptの `typeof` は、残念ながら「オブジェクトであること」しか教えてくれない。`typeof promise` は `’object’` だし、`typeof {}` もまた `’object’` だ。これに頼りきっていると、ライブラリ間をまたぐ複雑なデータフローの中で、思わぬバグが君のコードを食い荒らすことになる。

今日は、実務で遭遇する「Promiseの判定」という、一見単純だが実は奥が深いテーマを深掘りしていこう。

—

1. なぜ「`instanceof Promise`」だけでは不十分なのか

多くの初学者が最初にたどり着くのが `val instanceof Promise` だ。確かに、同一の実行コンテキスト(iframeをまたがない単一のウィンドウ環境)であれば、これでも動く。だが、現実はそう甘くない。

  • 異なるRealm(領域)の問題: ブラウザの別ウィンドウやiframeで生成されたPromiseを、親ウィンドウ側で判定しようとすると `instanceof` は無情にも `false` を返す。
  • 模造品(Thenable)の存在: `Promise` ではないが、`then` メソッドを持つオブジェクトが紛れ込むことはよくある。`Promise.resolve()` はこれらを自動的に飲み込んで解決してくれるが、君が書くユーティリティ関数が「Promiseインスタンスそのもの」を期待している場合、この挙動が仇となる。

—

2. 真のPromise判定:現場のスタンダード

現場で「こいつはPromiseか?」を判定する際の定石は、「thenableであるか?」を確認し、さらに「関数であるか?」を突き詰めることだ。

まずは、実務ですぐに使えるコードを見てほしい。

/

  • 与えられた値が「Promiseのようなもの(Thenable)」かどうかを判定する
  • @param {unknown} val
  • @returns {boolean}

/
function isThenable(val) {
// nullやundefinedを排除し、オブジェクトまたは関数であることを確認
// (typeof null は ‘object’ なので要注意)
return (
(typeof val === ‘object’ || typeof val === ‘function’) &&
val !== null &&
typeof val.then === ‘function’
);
}

/

  • より厳密に「Promiseインスタンス」であるかを確認する
  • @param {unknown} val
  • @returns {boolean}

/
function isPromise(val) {
// 1. まずはPromiseクラスのインスタンスであるかを確認
if (val instanceof Promise) return true;

// 2. インスタンスでない場合、Thenableかどうかを判定
// ここで isThenable を使うことで、異環境由来のPromiseもキャッチできる
return isThenable(val);
}

—

3. なぜ `typeof val.then === ‘function’` なのか

JavaScriptの仕様において、Promiseとは「`then` という名前のメソッドを持つオブジェクト」として定義されている(これを Thenable と呼ぶ)。

ブラウザのエンジン(V8など)は、`await` に渡された値に対して「お前はthenableか?」というチェックを内部的に行っている。我々が書くコードも、これに倣うのが最も堅牢だ。

現場での注意点:副作用に気をつけろ

このチェックには一点だけ、猛烈に注意すべき点がある。「ゲッター(Getter)」の存在だ。

もし、`then` プロパティに副作用のあるゲッターが定義されていたらどうなるか?

const dangerousObj = {
get then() {
console.log(“死の罠が発動!”);
return () => {};
}
};

// 判定しようとしただけでログが出る、あるいはエラーが起きる可能性がある
if (isThenable(dangerousObj)) { … }

実務で扱うデータソースが信頼できない(外部ライブラリの汚いオブジェクトなど)場合は、`try-catch` で囲うか、`Object.getOwnPropertyDescriptor` を使ってゲッターを事前に調査するような「防衛的プログラミング」が求められることもある。そこまでする必要があるかは、そのデータの「出所」と相談して決めるのが、プロの判断だ。

—

4. まとめ:明日から使えるアーキテクチャの心得

フロントエンドの設計において、データ型を疑うことは恥ではない。むしろ、「外部からのデータはすべて毒だと思え」というくらいの猜疑心が、君のアプリケーションを堅牢にする。

  • 簡単な判定: `isThenable` で十分なケースが9割。
  • 厳密な判定: 別ウィンドウとのやり取りがあるなら、`instanceof` に頼らず `then` メソッドの存在確認を優先する。
  • Promiseの仕様: `then` メソッドがあればそれはPromiseとして振る舞える。この「ダックタイピング」の精神を尊重しよう。

現場でバグに遭遇したとき、`typeof` や `instanceof` の壁にぶつかったら、今日話した「Thenableの正体」を思い出してほしい。その一歩先を知っているだけで、デバッグのスピードは劇的に変わるはずだ。

さて、コードに戻ろう。君のアプリケーションが、より美しく、そして壊れにくいものになることを期待しているよ。

コメント

タイトルとURLをコピーしました