6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

メモ:条件演算子(?:)とNull合体演算子(??)の違い

Last updated at Posted at 2022-04-27

概要

つい最近TypeScriptでコードを書いていて、条件演算子(?:)とNull合体演算子(??)の違いに引っかかったので忘れないようにそれぞれの違いと、どこに引っかかったのかをメモした記事です。

条件演算子(?:)

条件演算子は以下の形式で使用され、条件が真値であった場合に左辺を、条件が偽値であった場合に右辺を実行します。

条件 ? 左辺 : 右辺

JavaScriptで偽値として扱われるのは次の値です。

  • false
  • 0
  • 0n(BigInt)
  • 負の値
  • 空文字列("")
  • null
  • undefined
  • NaN

そのため、上記の値を条件として利用した場合は全て右辺が実行されます。

false ? "true value" : "false value"
// false value

0 ? "true value" : "false value"
// false value

"" ? "true value" : "false value"
// false value

null ? "true value" : "false value"
// false value

undefined ? "true value" : "false value"
// false value

Null合体演算子(??)

次にNull合体演算子(??)についてです。

Null合体演算子は以下の形で使用され、左辺が null または undefined の場合に右辺を返し、それ以外の場合に左辺を返します。

左辺 ?? 右辺

自分が引っかかったのがまさにここで、一部の書き方で利用する場合に同様の動作をするため、Null合体演算子(??)は条件演算子(?:)の記述と同じ条件で同じように動作すると勘違いしていました。

そのため、それぞれの演算子に null または undefined を利用する場合とそれ以外の場合で動作が異なることに気がつかず、想定外の動作が発生した時にはしばらく唸ってました。

もう少し具体的に見ていきます。

上記の説明の通り、Null合体演算子は左辺が null または undefined の場合に右辺を返します。
そのため、以下の記述はどちらもvalueundefinedの場合はfalse valueを返し、それ以外の場合はその値を返すという動作をします。

const value = undefined;
// string | undefined
const result1 = value ? value : "false value";
// false value

const result2 = value ?? "false value";
// false value

この場合は、結果的にNull合体演算子(??)で条件演算子(?:)の記述を省略した書き方になっています。

では、Null合体演算子(??)が条件演算子(?:)と同じ条件で同じように動作するだと勘違いしたまま次のようなコードを書くとどうなるでしょうか?

const number = Number(process.env.NUMBER) ?? 1
// process.env.NUMBERは string | undefined

// numberを利用した処理

上記のコードでは、numberに必ず数値が入ることを想定しています。

Null合体演算子(??)が条件演算子(?:)と同じ条件で同じように動作する場合、process.env.NUMBERが偽値の場合Number(process.env.NUMBER)も偽値(NaN)のためnumber1となり、以降の処理でも数値として扱われるため想定通りに動作します。

ただし、実際にはNull合体演算子(??)は 左辺が null または undefined の場合のみ右辺を返す演算子なので、左辺がNaNの場合はそのままNaNを返します。
そのため、以下のnumberを利用した処理で想定していない動作をすることになります(というか実際になりました)。

ちなみに以下のように書くと、想定している通りに処理ができます。

const number = Number(process.env.NUMBER || "1")

// numberを利用した処理

このように一部の状況では省略記法のように書くことができても根本の動作が違う場合、気がつかずにバグを生む可能性があります。

なので、新しいものを使うときはまずドキュメントを読みましょうという自戒を込めた記事でした。

参考文献

6
3
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?