Nullish Coalescing と Optional Chaining

3 min read読了の目安(約2200字

はじめに

今回の記事はjavascript,typescriptどちらでも利用可能であるNull合体演算子(Nullish Coalescing)とオプショナルチェイン(Optional Chaining)についての記事になります。


Optional Chainingの基本

interface User {
  name: string;
  age: number;
  address?: {//←ここでの?は省略可能を表す
    town: string;
  };
}

const user1: User = {
  name: "max",
  age: 22,
  address: {
    town: "Maple Town",
  },
};
const user2: User = {
  name: "Green",
  age: 19,
};
console.log(user1?.address?.town); //Maple Town
console.log(user2?.address?.town); //undifined

ここでは最後の?.に注目して下さい。これがOptional Chainingです。
?.演算子を使うと、チェーン内の各参照が正しいかどうかを明示的に確認せずにアクセスしていくことができます。途中のプロパティ(ここではaddressやtown)が存在していなかったら、(エラーを出さず)user2のように式が短絡されてundefinedを返してくれます。

ちなみにチェーンできるのはプロパティだけじゃなくメソッドの場合でも可能です。


Nullish Coalescingの基本

interface User {
  name: string;
  age: number;
  address?: {
    town: string;
  };
}

const user1: User = {
  name: "max",
  age: 22,
  address: {
    town: "Maple Town",
  },
};
const user2: User = {
  name: "Green",
  age: 19,
};

const town1 = user1.address?.town ?? "Tokiwa Town";
const town2 = user2.address?.town ?? "Tokiwa Town";
console.log(town1); //Maple Town
console.log(town2); //Tokiwa Town

上記のtown1やtown2で使用している ??これが nullish coalescing です。これは左辺がnull または undefinedのときだけ右辺(Tokiwa Town) が評価されます。

このケースでは??を次のように書き直すことが可能です。

const town1 = user1.address?.town || "Tokiwa Town";
const town2 = user2.address?.town || "Tokiwa Town";
console.log(town1); //Maple Town
console.log(town2); //Tokiwa Town

OR 演算子(||)に書き換えました。

??と||の違いは??は左辺がnull または undefinedのときだけ右辺(Tokiwa Town) が評価されるのに対し、||では左辺がfalsyな値(0,'',null,undefinedなど)であれば右辺が評価されるという違いがあります。
つまり||では 0 や空文字もスルーされてしまうので、より明示的なnullish coalescingのほうが望ましというわけです。


Optional ChainingとNullish Coalescing

最後に.???を組み合わせたコードを見てこの記事を終わりとします。

const pirate = [
  {
    name: "Luffy",

    address: {
      town: "Dawn Island",
    },
  },

  {
    name: "Zoro",

    address: {},
  },

  null,
];

for (let u of pirate) {
  const user = u ?? { name: "(Somebody)" };

  const town = u?.address?.town ?? "(Somewhere)";

  console.log(`${user.name} lives in ${town}`);
}
//Luffy lives in Dawn Island
//Zoro lives in (Somewhere)
//(Somebody) lives in (Somewhere)