TL;DR
JS/TS において、 falsey な値には色々とあるが、参照してランタイムエラーになってしまうのは null と undefined の2つである。
この null と undefined を合わせて nullish な値という。
falsey な値は || で判定・置き換えが可能だが、例えば '' はそのまま通したい、という場合もある。
JS/TS には nullish な値を簡潔に判定することができる ?? という演算子が用意されている。
Null 合体演算子 ??
左辺が null または undefined の場合左辺の値を返す。
それ以外は左辺の値を返す。
MDNには「論理OR演算子||の特殊形と見なせる」と書いてある。
コード例
null ?? 'foo' // 'foo'
undefined ?? 'foo' // 'foo'
false ?? 'foo' // false
0 ?? 'foo' // 0
-0 ?? 'foo' // -0
0n ?? 'foo' // 0n
NaN ?? 'foo' // NaN
'' ?? 'foo' // ''
document.all ?? 'foo' // HTMLAllCollection(...
なお ?? ではなく || で比較した場合、すべて 'foo' が返ってくる。
Null 合体代入 ??=
例えばx ??= y; は x = x ?? y; とほぼ同じ。
JS/TSの論理演算は短絡評価なので、 x が nullish でない場合、前者は代入自体が行われない。
後者は x が nullish であってもなくても代入が行われる。(短絡評価ではある)
コード例
let x;
x = null;
x ??= 'piyo'; // 'piyo'
x = undefined;
x ??= 'piyo'; // 'piyo'
x = false;
x ??= 'piyo'; // false
x = 0;
x ??= 'piyo'; // 0
x = -0;
x ??= 'piyo'; // -0
x = 0n;
x ??= 'piyo'; // 0n
x = NaN;
x ??= 'piyo'; // NaN
x = '';
x ??= 'piyo'; // ''
x = document.all;
x ??= 'piyo'; // HTMLALLCollection(...
なお ??= ではなく ||= を使った場合、 x にはすべて 'piyo' が代入される。