なぜ「安全なプロパティ取得」が業務で必須になるのか
業務コードで一番よく見るエラーの一つがこれです。
Cannot read properties of undefined (reading 'xxx')
JavaScriptつまり、
user.profile.address.city
JavaScriptのように「ネストしたプロパティ」を読もうとして、途中のどこかが undefined や null だった、というパターンです。
API レスポンス、外部サービスの結果、オプション引数、どれも「必ず入っている」とは限りません。
それなのに「ある前提」でプロパティを読んでしまうと、実行時にアプリが落ちます。
だからこそ、「途中が undefined でも落ちないで済む“安全なプロパティ取得”」をユーティリティとして持っておくと、
業務コードの安定性が一気に上がります。
まずは標準機能:オプショナルチェイニング(?.)を理解する
JavaScript には、すでに「安全なプロパティアクセス」を助けてくれる構文があります。
それが オプショナルチェイニング演算子 ?. です。
const city = user?.profile?.address?.city;
JavaScriptこれは、「user が null / undefined ならそこで止まり、city は undefined になる」という動きです。
const user1 = {
profile: {
address: {
city: "Tokyo",
},
},
};
const user2 = {}; // profile がない
console.log(user1?.profile?.address?.city); // "Tokyo"
console.log(user2?.profile?.address?.city); // undefined(エラーにならない)
JavaScript重要なポイントは、「途中で undefined があっても、例外にならずに undefined を返してくれる」ということです。
これだけでも、かなりの「安全なプロパティ取得」が実現できます。
「安全+デフォルト値」をセットにする
多くの場面では、「undefined ならそのまま undefined でいい」わけではなく、
「undefined ならデフォルト値を使いたい」ことが多いです。
例えば、「ユーザーの都市名。なければ '不明' と表示したい」というケース。
const city = user?.profile?.address?.city ?? "不明";
JavaScriptここでは、二つのポイントが組み合わさっています。
一つ目は、?. で「途中が undefined でも落ちない」ようにしていること。
二つ目は、??(null 合体演算子)で「最終結果が null / undefined なら '不明' にする」としていること。
この組み合わせだけで、「安全なプロパティ取得+デフォルト値補完」がかなりきれいに書けます。
ユーティリティ関数としての「安全なプロパティ取得」
構文だけでもかなり戦えますが、「パスを文字列や配列で指定したい」場面もあります。
例えば、「get(obj, 'profile.address.city') みたいに取りたい」というニーズです。
パスを配列で渡す安全取得
まずは、パスを配列で渡すシンプルなユーティリティを作ってみます。
function safeGet(obj, path) {
let current = obj;
for (const key of path) {
if (current == null) {
return undefined;
}
current = current[key];
}
return current;
}
JavaScript使い方はこうです。
const user = {
profile: {
address: {
city: "Tokyo",
},
},
};
console.log(safeGet(user, ["profile", "address", "city"])); // "Tokyo"
console.log(safeGet(user, ["profile", "company", "name"])); // undefined(エラーにならない)
console.log(safeGet(null, ["profile", "address"])); // undefined
JavaScriptここでの重要ポイントは、「途中で null / undefined を見つけたら、そこで undefined を返して終わる」というルールです。
これにより、「どこかが欠けていても絶対に例外にならない」ことが保証されます。
デフォルト値付きの safeGet
実務では、「undefined ならデフォルト値を返したい」ことがほとんどなので、
デフォルト値付きのバージョンを用意しておくと便利です。
function safeGetOr(obj, path, defaultValue) {
const value = safeGet(obj, path);
return value === undefined ? defaultValue : value;
}
JavaScript使い方です。
const city = safeGetOr(user, ["profile", "address", "city"], "不明");
const company = safeGetOr(user, ["profile", "company", "name"], "不明");
console.log(city); // "Tokyo"
console.log(company); // "不明"
JavaScriptここでのポイントは、「undefined のときだけデフォルトを使う」という挙動にしていることです。null をどう扱うかは要件次第ですが、「null は“意図的に空”とみなす」なら、この実装がちょうどよくなります。
パスを文字列で指定したい場合
「'profile.address.city' のような文字列で指定したい」ということもよくあります。
その場合は、文字列を分割してから safeGet に渡す形にできます。
function safeGetByPath(obj, pathString, separator = ".") {
if (!pathString) return obj;
const path = pathString.split(separator);
return safeGet(obj, path);
}
JavaScript使い方です。
const city = safeGetByPath(user, "profile.address.city");
const company = safeGetByPath(user, "profile.company.name");
console.log(city); // "Tokyo"
console.log(company); // undefined
JavaScriptさらにデフォルト値付きも簡単に作れます。
function safeGetByPathOr(obj, pathString, defaultValue, separator = ".") {
const value = safeGetByPath(obj, pathString, separator);
return value === undefined ? defaultValue : value;
}
JavaScript「安全なプロパティ取得」と「型チェック」を組み合わせる
安全に取得できても、「型が想定と違う」ことはよくあります。
例えば、「数値のはずが文字列だった」「配列のはずがオブジェクトだった」などです。
そこで、「安全取得 → 型チェック → デフォルト」という流れをユーティリティでまとめると、さらに実務向きになります。
例:数値として扱えるときだけ採用する
function safeGetNumberOr(obj, path, defaultValue) {
const value = safeGet(obj, path);
if (typeof value === "number" && Number.isFinite(value)) {
return value;
}
if (typeof value === "string") {
const n = Number(value);
if (Number.isFinite(n)) {
return n;
}
}
return defaultValue;
}
JavaScript使い方です。
const data = {
meta: {
page: "3",
},
};
const page = safeGetNumberOr(data, ["meta", "page"], 1);
console.log(page); // 3
JavaScriptここでは、「安全に取得する」だけでなく、「数値として妥当かどうか」まで見ています。
こうしておくと、「変な値が紛れ込んでも、内部では常に“まともな数値”として扱える」状態を作れます。
実務での具体的な利用イメージ
API レスポンスの防御的アクセス
外部 API のレスポンスは、仕様変更やバグで平気で形が変わります。
そこで、「安全なプロパティ取得」を挟んでおくと、アプリ全体が落ちにくくなります。
const userName = safeGetOr(apiResponse, ["user", "profile", "name"], "名無し");
const city = safeGetOr(apiResponse, ["user", "profile", "address", "city"], "不明");
JavaScriptこれなら、「user が null だった」「profile がなかった」という場合でも、
画面には最低限の情報を出しつつ、ログなどで異常を検知する、という設計ができます。
設定オブジェクトの読み取り
設定ファイルや環境変数から読み込んだオブジェクトも、欠けていることがよくあります。
const pageSize = safeGetNumberOr(config, ["paging", "pageSize"], 20);
const theme = safeGetOr(config, ["ui", "theme"], "light");
JavaScriptこうしておけば、「設定が一部欠けていても、アプリは動き続ける」状態を作れます。
小さな練習で感覚をつかむ
次のようなオブジェクトを用意して、自分で safeGet, safeGetOr, safeGetByPath, safeGetNumberOr を実装して試してみてください。
const data = {
user: {
profile: {
name: "山田",
address: {
city: "Tokyo",
},
},
},
};
JavaScript存在するパスと存在しないパスを混ぜて、
"user.profile.name"
"user.profile.address.city"
"user.profile.company.name"
"user.settings.theme"
JavaScriptなどを安全取得してみると、「どこで落ちなくなるのか」「どこでデフォルトが効くのか」が体感できます。
ここまでできれば、「安全なプロパティ取得」はもう実務レベルです。
あとは、あなたのプロジェクトに合わせて、「数値版」「配列版」「真偽値版」などを少しずつ増やしていけば、
“外から来るどんなデータにも折れないコード”に近づいていきます。
