オプショナルチェーン ?.

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

オプショナルチェーン ?. とは

?. でネストした値を安全に取り出し、null / undefined のときも例外を出さずに undefined を返そう。

オプショナルチェーン ?. で深い値を安全に取り出す

JavaScript でとてもよく遭遇するエラーが、TypeError: Cannot read properties of undefined (reading 'name') です。これは user.profile.name のようにネストしたオブジェクトの値を取り出そうとして、途中の user.profileundefined だったときに発生します。古い書き方では、各階層ごとに if で存在チェックをする必要があって、コードがどんどん長くなっていました。

この面倒を解決する演算子が オプショナルチェーン ?. です。ES2020 で追加され、書式は obj?.prop で「objnull / undefined ならその場で undefined を返し、それ以外は通常通り prop を取り出す」という動きをします。

?. は「途中で止まる安全弁」です。連鎖の途中が nullundefined でも、エラーにせず undefined を返してくれます。

文法の基本

書き方は、ピリオドの代わりに ?. を使うだけです。

JavaScript

const user = { name: "Naoki" }; console.log(user?.name); // "Naoki" console.log(user?.profile?.bio); // undefined 途中で止まる console.log(user?.profile?.bio?.toUpperCase()); // undefined 関数呼び出しも安全

user.profileundefined の時点で、続く ?.bio評価されず 全体が undefined になります。これを ?. 無しで書くと次のような恐ろしさです。

JavaScript

const user = { name: "Naoki" }; console.log(user.profile.bio); // TypeError で停止

アプリケーションが落ちる原因になるので、ネストしたアクセスは原則として ?. を使うのが安全です。

3 つの使い方

?. は次の 3 つのパターンで使えます。

  • プロパティアクセスobj?.prop
  • 配列の要素アクセスarr?.[0]
  • 関数呼び出しfn?.()

それぞれの例を見てみます。

JavaScript

const data = null; console.log(data?.users); // undefined プロパティアクセス console.log(data?.["users"]); // undefined ブラケット記法も OK const arr = null; console.log(arr?.[0]); // undefined 配列アクセス const maybeFn = undefined; console.log(maybeFn?.()); // undefined 関数呼び出し

どれも「左が null / undefined なら止まる」という共通ルールです。これだけで、if (data && data.users && data.users[0]) のような長い守りのコードがほぼ消えます。

Mermaid で ?. の挙動を追う

user?.profile?.name の評価フローを図にすると次のとおりです。

diagram (will load when visible)

各階層で「nullundefined か」を確認し、見つかった瞬間に undefined を返します。3 階層、4 階層と深くなっても同じパターンが繰り返されるだけなので、コードがネストしません。

?? と組み合わせると最強

?.?? を組み合わせると、「ネスト値を安全に取り出して、無ければデフォルト」という超頻出パターンが 1 行で書けます。

JavaScript

const user = null; const displayName = user?.profile?.name ?? "ゲスト"; console.log(displayName); // "ゲスト"

user?.profile?.nameundefined になっても、?? がデフォルト値 "ゲスト" を返すので、UI に表示する文字列が必ず確保できます。これは ReactVue のテンプレートでも超頻出のパターンです。

?.?? はセットで覚えると効果倍増です。undefined の連鎖を ?? でキャッチするイメージを持ってください。

よくある間違い

?. の落とし穴を 3 つ紹介します。

  • ?. を全部にバラまくa?.b?.c?.d?.e のように毎階層に ?. を付けると、本来 null / undefined であってはいけない場所のバグを 隠してしまう ことがあります。あくまでも「本当に欠ける可能性がある場所」だけに付ける、というのが理想です
  • ?. の右側に = を書くobj?.prop = value は構文エラーです。?.読み取り専用。代入は if (obj) obj.prop = value; のように分岐させる必要があります
  • ?.? (三項演算子) を混同するobj?.prop は安全アクセス、obj ? a : b は条件分岐です。スペースの有無で意味が変わるので、エディタの色分けで区別する習慣を

もうひとつ、falsynullish の違いに引きずられないように注意してください。

JavaScript

const obj = { count: 0 }; console.log(obj?.count); // 0 正しく取れる console.log(obj?.count || "なし"); // "なし" 0 が falsy で上書き console.log(obj?.count ?? "なし"); // 0 のまま 正しい

0 を正常な値として残したいなら、|| ではなく ?? を組み合わせるのが正解です。

?. は「左が nullish か」を見る演算子、?? も「左が nullish か」を見る演算子。両者は 同じ判定基準 を共有しているのが嬉しいポイントです。

やってみよう

それでは課題に取り組みましょう。getCity(user) を完成させて、user.address.city を安全に取り出してください。途中の useruser.addressnull / undefined でも例外を出さず、undefined を返してください。

書き方の方針は次のとおりです。

  • return user?.address?.city; の 1 行で完成
  • if (user && user.address && user.address.city) のような古いガード書きを避ける
  • 引数が null でも undefined でも、テストは undefined を期待

?. を使いこなせるようになると、API レスポンスの取り扱いがぐっと楽になります。プロのフロントエンド開発では毎日のように使う必須演算子です。

よくある質問

Q. ブラウザと Node.js で動作は変わりますか?

A. JavaScript の構文・組み込み機能(配列・文字列・Promise 等)はどちらでも同じです。違いは DOM API(ブラウザ専用)と fs などのファイル系(Node 専用)など、実行環境固有の機能です。コアロジックは両方で動くため、テストもしやすくなります。

Q. ES6 以降の新機能は使っても大丈夫ですか?

A. 現代のブラウザ・Node.js は ES2020 以降の機能をほぼサポートしています。古い IE 等を対象にする必要が無ければ、let/const、アロー関数、分割代入、async/await を積極的に使ってください。トランスパイル(Babel/Vite)が必要なケースは年々減っています。

Q. TypeScript に進む価値はありますか?

A. 型情報があるとリファクタやエディタ補完が劇的に効くため、規模が大きくなるなら TypeScript への移行を強くおすすめします。最初は any を許容しつつ徐々に型を付ければ、JS の知識をそのまま活かせます。

次のレッスン

次は ビット演算で偶数判定 で、`? を学びます。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. ?. 演算子 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. ?. 演算子 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. 関数名は getCity、引数は user の 1 つにすること
  2. プロパティアクセスには ?. を使うこと
  3. if 文や && ガードを使わずに 1 行で書くこと

入出力例

test-cases.txt

getCity({"address":{"city":"Tokyo"}})"Tokyo" getCity({})undefined getCity({"address":{}})undefined getCity(null)undefined getCity({"address":{"city":"Osaka"}})"Osaka"

ヒント

main.js
main.js
学習モード

メモ

オプショナルチェーン ?.

⌘S で保存