ryokatsu.dev

Object.{pick, omit}のプロポーザルが良さそう


Object.{pick, omit}

TC39のプロポーザルでObject.{pick, omit}がStage1に昇格していて使えたら便利そうだったので紹介します。

※提案段階なので変更される可能性があります

プロポーザル通りですが、あるオブジェクトの中から選択したkeyからなる新しいオブジェクトまたは、選択した以外のオブジェクトを新たに作成することができます。現状では、以下のような関数を作って行っていました。


const pick = (obj, keys) => Object.fromEntries(
    keys.map(k => obj.hasOwnProperty(k) && [k, obj[k]]).filter(x => x)
);

const omit = (obj, keys) => Object.fromEntries(
    keys.map(k => !obj.hasOwnProperty(k) && [k, obj[k]]).filter(x => x)
);

関数的にはこれでも読めば理解できますが、直感的ではないのでこれを解決する提案です。かの有名なLodashでも、_.pick_.omitのメソッドが用意されているのでこちらを使うケースが多いかもです。

// Pickする例
const object = { 'a': 1, 'b': '2', 'c': 3 };

_.pick(object, ['a', 'c']);
// { 'a': 1, 'c': 3 }

今回提案されているプロポーザルでもほぼLodashと同じような構文になっています。


Object.pick({a : 1, b : 2}, ['a']); // => {a: 1}
Object.omit({a : 1, b : 2}, ['b']); // => {a: 1}

細かい箇所

  • プロトタイプチェーンは省略できます。
  • __proto__になっていても使えるが非推奨なのであんまり使わない方がいいかも
  • 戻り値はプレーンなオブジェクト
  • Symbolで使いたい時はSymbol.iteratorをpickかomitした後にkeyを指定して実行(一度プロパティとして定義する)
  • エラーをthrowする場合はまだどうするか検討する必要ありそうだけど一旦は以下を想定しているっぽい
Object.pick(Object.defineProperty({}, 'key', {
   get() { throw new Error() }
}), ['key']);
  • Lodashの_.pickbyとかは引数として組み合わせることで再現可能
Object.pick({a : 1, b : 2}, v => v);