メインコンテンツまでスキップ

オプショナルチェーン (optional chaining)

JavaScriptのオプショナルチェーン?.は、オブジェクトのプロパティが存在しない場合でも、エラーを起こさずにプロパティを参照できる安全な方法です。

プロパティ参照がエラーになる問題

JavaScriptではnullundefinedのプロパティを参照するとエラーが発生します。

js
const book = undefined;
const title = book.title;
TypeError: Cannot read property 'title' of undefined
 
const author = null;
const email = author.email;
TypeError: Cannot read property 'email' of null
js
const book = undefined;
const title = book.title;
TypeError: Cannot read property 'title' of undefined
 
const author = null;
const email = author.email;
TypeError: Cannot read property 'email' of null

エラーを避けるには、値がnullundefinedでないかチェックする必要があります。

js
const book = undefined;
const title = book === null || book === undefined ? undefined : book.title;
console.log(title);
undefined
js
const book = undefined;
const title = book === null || book === undefined ? undefined : book.title;
console.log(title);
undefined
js
const book = { title: "サバイバルTypeScript" };
const title = book === null || book === undefined ? undefined : book.title;
console.log(title);
"サバイバルTypeScript"
js
const book = { title: "サバイバルTypeScript" };
const title = book === null || book === undefined ? undefined : book.title;
console.log(title);
"サバイバルTypeScript"

ネストしたオブジェクトの場合、チェック処理はいっそう複雑になってきます。

js
const book = { author: { email: "alice@example.com" } };
const authorEmail =
book === null || book === undefined
? undefined
: book.author === null || book.author === undefined
? undefined
: book.author.email;
js
const book = { author: { email: "alice@example.com" } };
const authorEmail =
book === null || book === undefined
? undefined
: book.author === null || book.author === undefined
? undefined
: book.author.email;

チェックすればエラーなく動きますが、記述量が多くなるという課題もあります。

オプショナルチェーン

JavaScriptのオプショナルチェーンはnullundefinedのプロパティを誤って参照しないようにしつつ、記述量を抑えられる書き方です。オプショナルチェーンは?.演算子を用いて書きます。

js
const book = undefined;
const title = book?.title;
// ^^オプショナルチェーン
console.log(title);
undefined
js
const book = undefined;
const title = book?.title;
// ^^オプショナルチェーン
console.log(title);
undefined
js
const book = { title: "サバイバルTypeScript" };
const title = book?.title;
console.log(title);
"サバイバルTypeScript"
js
const book = { title: "サバイバルTypeScript" };
const title = book?.title;
console.log(title);
"サバイバルTypeScript"

オプショナルチェーンはネストして使うこともできます。

js
const book = undefined;
const authorEmail = book?.author?.email;
console.log(authorEmail);
undefined
js
const book = undefined;
const authorEmail = book?.author?.email;
console.log(authorEmail);
undefined
js
const book = { author: { email: "alice@example.com" } };
const authorEmail = book?.author?.email;
console.log(authorEmail);
"alice@example.com"
js
const book = { author: { email: "alice@example.com" } };
const authorEmail = book?.author?.email;
console.log(authorEmail);
"alice@example.com"

もしも?.に先行する変数やプロパティの値がnullまたはundefinedのときは、その先のプロパティは評価されず、undefinedが返ります。

js
const book = null;
console.log(book?.title);
undefined
js
const book = null;
console.log(book?.title);
undefined
js
const book = { author: null };
console.log(book.author?.name);
undefined
js
const book = { author: null };
console.log(book.author?.name);
undefined

関数呼び出し

関数を呼び出すときにもオプショナルチェーンが使えます。関数に使う場合は、引数カッコの前に?.を書きます。

js
const increment = undefined;
const result = increment?.(1);
console.log(result);
undefined
js
const increment = undefined;
const result = increment?.(1);
console.log(result);
undefined
js
const increment = (n) => n + 1;
const result = increment?.(1);
console.log(result);
2
js
const increment = (n) => n + 1;
const result = increment?.(1);
console.log(result);
2

メソッドを呼び出すときも同様の書き方です。

js
const book = { getPrice: undefined };
console.log(book.getPrice?.());
undefined
js
const book = { getPrice: undefined };
console.log(book.getPrice?.());
undefined
js
const book = {
getPrice() {
return 0;
},
};
console.log(book.getPrice?.());
0
js
const book = {
getPrice() {
return 0;
},
};
console.log(book.getPrice?.());
0

配列要素の参照

配列要素を参照する際にもオプショナルチェーンが使えます。要素を参照する場合は、カギカッコの前に?.を書きます。

js
const books = undefined;
const title = books?.[0];
console.log(title);
undefined
js
const books = undefined;
const title = books?.[0];
console.log(title);
undefined
js
const books = ["サバイバルTypeScript"];
const title = books?.[0];
console.log(title);
"サバイバルTypeScript"
js
const books = ["サバイバルTypeScript"];
const title = books?.[0];
console.log(title);
"サバイバルTypeScript"

TypeScriptでの型

TypeScriptでオプショナルチェーンを使った場合、得られる値の型は、最後のプロパティの型とundefinedのユニオン型になります。

ts
let book: undefined | { title: string };
const title = book?.title;
const title: string | undefined
ts
let book: undefined | { title: string };
const title = book?.title;
const title: string | undefined

TypeScriptのコンパイル結果

TypeScriptのコンパイラーオプションtargetes2020以上のときは、オプショナルチェーンはそのままJavaScriptにコンパイルされます。

ts
const title = book?.title;
 
ts
const title = book?.title;
 

targetes2019以前の場合は、次のような三項演算子を用いたコードにコンパイルされます。

ts
const title = book === null || book === void 0 ? void 0 : book.title;
 
ts
const title = book === null || book === void 0 ? void 0 : book.title;
 

Null合体演算子と組み合わせる

オプショナルチェーンがundefinedを返したときに、デフォルト値を代入したい場合があります。その際には、Null合体演算子??を用いると便利です。

js
const book = undefined;
const title = book?.title ?? "デフォルトタイトル";
console.log(title);
"デフォルトタイトル"
js
const book = undefined;
const title = book?.title ?? "デフォルトタイトル";
console.log(title);
"デフォルトタイトル"
学びをシェアする

・JavaScriptのオプショナルチェーン?.は安全にプロパティを参照する方法
・値がnullかundefinedのときundefinedが返る
・a?.b?.cのようにネストも可能
・関数は?.()
・配列は?.[]
・TypeScriptでは値の型とundefinedのユニオン型になる
・Null合体演算子と相性がいい

『サバイバルTypeScript』より

この内容をツイートする

関連情報

📄️ 配列要素へのアクセス

JavaScriptでの配列要素アクセス

📄️ 三項演算子

JavaScriptの三項演算子(ternary operator)は、条件分岐ができる演算子です。条件式、真の場合の値、偽の場合の値の三項を取るため三項演算子と呼ばれています。