「存在チェック付き実行」とは何を守りたいのか
存在チェック付き実行は、一言でいうと
「その値が“本当に実行していい関数か”を確認してから呼ぶ」ためのパターンです。
業務コードでよくあるのが、こういうやつです。
options.onSuccess(result);
JavaScriptでも実際には、onSuccess が渡されていないこともあります。
そのときに何も考えずに呼ぶと、
TypeError: options.onSuccess is not a function
JavaScriptでアプリが落ちます。
「あるかもしれないし、ないかもしれないコールバック」
「関数かもしれないし、別の型かもしれない値」
こういう“あいまいなもの”を安全に扱うために、
「存在チェック付き実行」というユーティリティを持っておくと、コードが一気に安定します。
まずは基本形:if で存在と型をチェックしてから実行
いちばん素直な書き方はこれです。
if (typeof options.onSuccess === "function") {
options.onSuccess(result);
}
JavaScriptここでやっていることは二つです。
一つ目は、「options.onSuccess が undefined / null ではないか」を暗黙にチェックしていることです。typeof undefined も typeof null も "function" にはならないので、存在しなければ if の中に入りません。
二つ目は、「型が function であること」を確認していることです。
もし誰かが間違えて onSuccess: true のような値を渡しても、実行されずにスルーされます。
このパターンを毎回書くのは面倒なので、ユーティリティ関数にしてしまうのが「存在チェック付き実行」です。
ユーティリティ化した「存在チェック付き実行」
関数を受け取って、「関数なら実行する、そうでなければ何もしない」小さなユーティリティを作ってみます。
function runIfFunction(fn, ...args) {
if (typeof fn === "function") {
return fn(...args);
}
return undefined;
}
JavaScript使い方はとてもシンプルです。
runIfFunction(options.onSuccess, result);
runIfFunction(options.onError, error);
JavaScriptここでの重要ポイントは三つあります。
一つ目は、「呼び出し側から if 文が消える」ことです。
毎回 if (typeof ...) と書かなくてよくなり、「存在チェック付き実行」という意図が関数名に集約されます。
二つ目は、「引数を可変長で受け取って、そのまま渡している」ことです。
これにより、runIfFunction(fn, a, b, c) のように、どんな関数にも使い回せます。
三つ目は、「戻り値をそのまま返している」ことです。
関数が何か値を返す場合、それをそのまま受け取ることもできますし、
「関数がなかったときは undefined が返る」という仕様も分かりやすくなります。
オプショナルチェイニング ?.() との違いと使い分け
JavaScript には、関数呼び出しにも使えるオプショナルチェイニングがあります。
options.onSuccess?.(result);
JavaScriptこれは、「onSuccess が null / undefined でなければ呼ぶ」という構文です。
ただし、ここで注意したいのは、「型チェックはしていない」という点です。
const options = {
onSuccess: true,
};
options.onSuccess?.(); // TypeError: options.onSuccess is not a function
JavaScript?. は「存在チェック」はしてくれますが、「それが関数かどうか」までは見てくれません。
一方、runIfFunction は typeof fn === "function" を見ているので、
「関数以外が来たら何もしない」という安全性があります。
つまり、
構文として手軽に書きたいだけなら fn?.()
「関数であることまで保証したい」「外部から何が来るか分からない」なら runIfFunction
という使い分けができます。
デフォルト動作付きの「存在チェック付き実行」
ときどき、「関数がなかったら、代わりにこの処理をしたい」という場面があります。
例えば、「onSuccess がなければログだけ出す」などです。
その場合は、デフォルト動作付きのユーティリティを作れます。
function runIfFunctionOr(fn, fallback, ...args) {
if (typeof fn === "function") {
return fn(...args);
}
if (typeof fallback === "function") {
return fallback(...args);
}
return undefined;
}
JavaScript使い方の例です。
runIfFunctionOr(
options.onSuccess,
(result) => {
console.log("成功:", result);
},
result
);
JavaScriptここでは、「onSuccess があればそれを呼ぶ。なければログを出す」という振る舞いを一行で表現しています。
「存在チェック付き実行」に「フォールバック処理」を足したイメージです。
非同期関数(Promise / async)に対する存在チェック付き実行
業務では、コールバックが async 関数であることも多いです。
その場合は、戻り値が Promise になるので、await 付きで扱えるユーティリティがあると便利です。
async function runIfAsyncFunction(fn, ...args) {
if (typeof fn === "function") {
return await fn(...args);
}
return undefined;
}
JavaScript使い方です。
await runIfAsyncFunction(options.onLoaded, data);
JavaScriptここでも、「関数でなければ何もしない」「関数なら await して結果を返す」というシンプルなルールにしています。
「存在チェック付き実行」を非同期の世界に持ち込んだだけですが、
API フックやライフサイクルイベントなどでかなり使えます。
実務での具体的な利用シーン
コールバックオプションを持つ関数
例えば、データ取得関数に「成功時」「失敗時」のコールバックをオプションで渡せるようにしたいとします。
async function fetchUser(options = {}) {
try {
const res = await fetch("/api/user");
const data = await res.json();
runIfFunction(options.onSuccess, data);
return data;
} catch (error) {
runIfFunction(options.onError, error);
throw error;
}
}
JavaScript呼び出し側は、必要なコールバックだけ渡せばよくなります。
fetchUser({
onSuccess(user) {
console.log("ユーザー取得:", user);
},
});
JavaScriptここでのポイントは、「コールバックが渡されていなくても絶対に落ちない」ことです。runIfFunction が「存在チェック付き実行」を一手に引き受けてくれているので、fetchUser の中はとても読みやすくなります。
UI イベントハンドラのオプション実行
UI コンポーネントで、「親から渡されるかもしれないイベントハンドラ」を呼ぶ場面も典型的です。
function Button(props) {
function handleClick(event) {
runIfFunction(props.onClick, event);
}
// 仮の JSX 風
return `<button>...</button>`;
}
JavaScript親側は、onClick を渡してもいいし、渡さなくてもいい。
子側は、「存在チェック付き実行」で安全に呼ぶ。
このパターンは、コンポーネント設計の基本パターンの一つです。
存在チェック付き実行と「安全処理」の関係
ここまで見てきたように、「存在チェック付き実行」は、
「呼び出し先が本当に“実行可能な関数”かどうか分からない」状況での安全装置です。
安全な JSON parse
安全な JSON stringify
try-catch ラッパー
安全なプロパティ取得
オプショナル取得
と同じ系統で、「外から来るものを信用しない」という姿勢の一部です。
存在チェック付き実行をユーティリティとして持っておくと、
「このコールバック、本当にあるのかな」
「これ、関数じゃない値が来たらどうなるんだろう」
と毎回不安にならずに、
「とりあえず runIfFunction 経由で呼べば落ちない」という安心感を持って書けるようになります。
小さな練習で感覚をつかむ
次のような値を用意して、自分で runIfFunction と runIfFunctionOr を実装して試してみてください。
const f1 = () => console.log("呼ばれた");
const f2 = "関数じゃない";
const f3 = null;
JavaScriptそれぞれに対して、
runIfFunction(f1);
runIfFunction(f2);
runIfFunction(f3);
runIfFunctionOr(f1, () => console.log("フォールバック"));
runIfFunctionOr(f2, () => console.log("フォールバック"));
JavaScriptを実行してみると、「どのケースで何が起きるか」「どこで何もしないで済むか」が体感できます。
ここまで来れば、「存在チェック付き実行」はもうあなたの武器です。
あとは、実際のプロジェクトの中で「ここ、たまに undefined が来るんだよな」という場所に、
少しずつこのパターンを差し込んでいけば、コードの“壊れにくさ”がじわじわ上がっていきます。
