lamechang-dev

Webフロントエンドエンジニア lamechangのブログ。

【JavaScript/TypeScript】条件に応じてオブジェクトのプロパティを追加する方法

※ ES6以上の動作環境

JavaScriptにおいて、条件に応じて(Conditionallyに)オブジェクトのプロパティを付与する方法について一応書きます。書こうと思った動機は「意外と頻出な実装パターンに見えてあまり日本語の情報にヒットしなかった」から困ってる人いるかも?くらいの気持ちですね😿

javascript conditionally add property to object とかでググれば速攻で答えに辿り着きます。

早速ですが具体例を紹介します。以下のようにオブジェクト taro に対して、特定の条件においてプロパティ wifename を付与したいような状況です。

const isMarried = false;
const taro = {
  age: 25,
  ...(isMarried && { wifename: "hanako" })
};

console.log(taro);

この記法について、今回のようなシンプルな例だと分かりやすくはあるんですが、実際の現場ではここまで実装で扱うオブジェクト構造などがシンプルになることなど基本的になく、「場合によっては可読性が低くなるのでで避けるべきではないか?」とちょっと思ったりしました。

が、意外と処理を追って見るとそんなこともない、という結論に至りました。

spread operatorの挙動は原則 Object.assign()と同様であり、上記の記述は以下のように書き直すことができます

const taro = {
  age: 25,
  ...(isMarried && { wifename: "hanako" })
};

// 以下のように表現できる
Object.assign({ age: 25 }, isMarried && { wifename: "hanako" })

この時、 isMarriedがfalseのケースでは以下のような処理になります(これはもちろん論理演算子の挙動)

Object.assign({ age: 25 }, false)

ここでObject.assign()は、すべてのプリミティブ(未定義なども含む)を{}と同じように扱うようなので、空のオブジェクトがマージされたことになり意図した挙動が実現できているといった感じです。大してややこしい話ではないですね。😄

Object.assign()は、すべてのプリミティブ(未定義なども含む)を{}と同じように扱う という挙動を知ってるかどうかかなと思います。

補足

TypeScript(4.5.4で確認)環境だと以下のように booleanをspread operatorで展開しようとする際に以下のようなエラーを吐きます。

const taro = {
  age: 25,
  // Spread types may only be created from object types.ts(2698)
  ...(isMarried && { wifename: "hanako" })
};

こちらについては as による型アサーションを行うのも手かとも思うのですが、やはり予期せぬバグを生みかねないので、素直に三項演算子で書いてあげて良いのではないかと思います。

const taro = {
  age: 25,
  ...(isMarried ? { wifename: "hanako" } : {})
};