JavaScriptでの開発において、もっとも頻繁に遭遇するエラーの一つが「TypeError: Cannot read property ‘…’ of undefined」です。
ネストされた深い構造を持つオブジェクトから特定のプロパティを参照しようとする際、途中のプロパティが存在しないだけでプログラム全体が停止してしまう問題は、多くのエンジニアを悩ませてきました。
このような課題を劇的に解決し、コードの堅牢性と可読性を同時に向上させる機能がオプショナルチェーン(Optional Chaining)です。
オプショナルチェーンは、参照が null または undefined の可能性がある場合に、エラーを投げずに安全にアクセスを試みるための構文です。
本記事では、オプショナルチェーンの基本構文から、実務で役立つ具体的な記述パターン、そして使用時に注意すべきポイントまで詳しく解説します。
オプショナルチェーンの基本概念と構文
オプショナルチェーン(?.)は、接続されたプロパティが存在しない場合に、エラーを発生させる代わりに undefined を返却する仕組みです。
かつては、深い階層にあるデータにアクセスするために、論理演算子の && を連結して「存在チェック」を繰り返す必要がありました。
しかし、オプショナルチェーンを用いることで、記述を大幅に簡略化できます。
基本的なプロパティアクセス
まずは、もっとも一般的なオブジェクトのプロパティ参照における例を見てみましょう。
const user = {
profile: {
name: "田中 太郎"
}
};
// 従来の書き方(&&演算子を使用)
const legacyName = user && user.profile && user.profile.name;
// オプショナルチェーンを使用した書き方
const modernName = user?.profile?.name;
console.log(modernName);
田中 太郎
もし、user.profile が存在しなかった場合、従来の書き方ではエラーを防ぐために冗長なチェックが必要でしたが、オプショナルチェーンなら ?. を置くだけで安全に処理を継続できます。
短絡評価(ショートサーキット)の仕組み
オプショナルチェーンの重要な特性に、短絡評価があります。
?. の左側の値が null または undefined であると判定された瞬間、それ以降の右側のプロパティアクセスやメソッド実行は一切行われません。
let count = 0;
const data = null;
// dataがnullなので、count++ は実行されない
const result = data?.[count++];
console.log(result);
console.log(count);
undefined
0
この挙動により、不要な計算や副作用を避けることができるため、パフォーマンスや予期せぬ挙動の防止に寄与します。
実戦的な記述パターン:配列と関数の安全な呼び出し
オプショナルチェーンは、オブジェクトのプロパティアクセス以外にも、配列の要素アクセスや関数の実行においても威力を発揮します。
配列の要素へのアクセス
APIから取得したデータが配列である保証がない場合や、特定のインデックスが空である可能性がある場合に有効です。
ブラケット記法([])の前に ?. を配置します。
const users = null;
// 配列がnullでもエラーにならない
const firstUser = users?.[0];
console.log(firstUser);
undefined
関数の安全な実行
コールバック関数を引数として受け取る場合や、オブジェクトのメソッドが動的に定義される場合に役立ちます。
関数名の後に ?.() と記述します。
const helper = {
// log: (msg) => console.log(msg) // 定義されていない可能性がある
};
// メソッドが存在する場合のみ実行する
helper.log?.("実行されました");
console.log("プログラムは継続しています");
プログラムは継続しています
この記述パターンは、特にイベントハンドラーやプラグインの拡張ポイントなど、「関数が定義されていれば実行し、なければ何もしない」というロジックを実装する際に非常に便利です。
Null合体演算子(??)との組み合わせ
オプショナルチェーンは、単体でも強力ですが、Null合体演算子(??)と組み合わせることで真価を発揮します。
オプショナルチェーンによって得られた結果が undefined の場合に、デフォルト値を設定するパターンです。
デフォルト値の設定
APIのレスポンスが不完全な場合でも、アプリケーションの表示を崩さないためにデフォルト値を適用する例を見てみましょう。
const apiResponse = {
settings: {
theme: null
}
};
// themeが存在しない、またはnullの場合は 'light' を代入
const currentTheme = apiResponse.settings?.theme ?? 'light';
// 存在しないプロパティへのアクセス
const fontSize = apiResponse.settings?.layout?.fontSize ?? 16;
console.log(`Theme: ${currentTheme}`);
console.log(`Font Size: ${fontSize}`);
Theme: light
Font Size: 16
以前は論理和演算子(||)が使われていましたが、これは「数値の0」や「空文字 “”」などの Falsy(偽値) もデフォルト値に上書きしてしまうという問題がありました。
?? を使用すれば、厳密に null または undefined の時のみデフォルト値を適用できるため、意図しないバグを防げます。
オプショナルチェーン使用時の注意点とアンチパターン
非常に便利なオプショナルチェーンですが、どこにでも使えば良いというわけではありません。
不適切な使用は、かえってデバッグを困難にすることがあります。
1. バグを隠蔽してしまうリスク
オプショナルチェーンは、値が存在しない場合にエラーを「握りつぶす」効果があります。
本来であれば存在するはずのデータが欠落している場合、エラーが発生しないために問題の発覚が遅れる可能性があります。
| 使用シーン | 推奨されるアプローチ |
|---|---|
| 設定ファイルや必須データ | オプショナルチェーンを使わず、エラーを発生させて不備を検知する |
| 外部APIやユーザー入力 | オプショナルチェーンで安全に処理し、必要に応じてバリデーションを行う |
| 任意指定のコールバック | オプショナルチェーンを使用して柔軟に対応する |
「ここには絶対にデータがあるはずだ」という確信がある場所では、あえて使わないという選択も重要です。
2. 代入演算の左辺には使用できない
オプショナルチェーンは、値を読み取るための構文です。
そのため、値を代入しようとすると構文エラー(SyntaxError)が発生します。
const user = {};
// エラーになる例
// user?.name = "鈴木"; // SyntaxError: Invalid left-hand side in assignment
代入を行いたい場合は、事前にオブジェクトの存在を確認するか、従来通りの条件分岐を使用する必要があります。
3. オプショナルチェーンの濫用による可読性の低下
すべてのプロパティアクセスに ?. を付けてしまうと、コードが煩雑になり、どのデータが本当にオプショナル(任意)なのかが判別できなくなります。
// 悪い例:すべての階層に付けてしまい、意図が不明確
const value = a?.b?.c?.d?.e?.f;
データ構造を理解した上で、「どこでデータが途切れる可能性があるか」を見極めて適切に配置することが、クリーンなコードを書くコツです。
実務での活用事例:APIレスポンスの処理
実務でもっともオプショナルチェーンが活躍するのは、外部APIから取得した複雑なJSONデータを処理する場面です。
async function getUserDisplayInfo(userId) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
const data = await response.json();
// 複雑なネスト構造を安全に走査
return {
userName: data.profile?.basicInfo?.nickname ?? "ゲストユーザー",
lastLogin: data.stats?.loginHistory?.[0]?.date ?? "ログイン履歴なし",
premiumStatus: data.subscription?.plan?.isActive ? "プレミアム" : "無料会員"
};
} catch (error) {
console.error("データの取得に失敗しました", error);
return null;
}
}
このコードでは、nickname がない場合、loginHistory 配列が空の場合、あるいは subscription 自体が存在しない場合でも、プログラムはクラッシュすることなく適切なデフォルト値を返却できます。
互換性と最新の動向
2026年現在、オプショナルチェーンは主要なブラウザおよびランタイム(Node.js, Deno, Bunなど)ですべてサポートされています。
以前はBabelなどのトランスパイラを介して使用することが一般的でしたが、現在はネイティブ環境でそのまま記述しても問題ありません。
TypeScript環境においても、オプショナルチェーンは型定義と強力に連携します。
インターフェースでプロパティがオプショナル(name?: string)として定義されている場合、TypeScriptコンパイラはオプショナルチェーンの使用を推奨し、安全なコード作成を支援してくれます。
まとめ
JavaScriptのオプショナルチェーン(?.)は、現代のWeb開発において欠かすことのできない機能です。
- 深い階層のアクセスを安全に行える
- 短絡評価により無駄な処理を防げる
- Null合体演算子(??)との組み合わせで柔軟なデータ処理が可能
これら三つのメリットを最大限に活かすことで、エラーに強く、メンテナンス性の高いコードを実現できます。
一方で、エラーを意図せず隠蔽してしまわないよう、データの重要性に応じて適切に使い分ける「判断力」も求められます。
今回紹介したパターンを参考に、ぜひ日々のコーディングにオプショナルチェーンを取り入れ、「落ちないJavaScriptプログラム」を目指してください。
