Object.{pick,omit}

You are correct. It would just be a shortcut of that, but without having to introduce a bunch of local variables into the current scope (yes, there's other ways of doing this shortcut, but they all have little downsides).

Though, if we introduce both a pick syntax and a pick function, your version is just a shortcut for this:

// before
const newObj = oldObj.[key1, key2]
// after
const newObj = Object.pick(oldObj, [key1, key2])

Even without Object.pick(), there's a slightly verbose shortcut for this too:

const newObj = {
  [key1]: oldObj[key1],
  [key2]: oldObj[key2],
}

If we're ignoring use cases that have shortcuts, then the only value the oldObj.[] syntax brings is for this specific scenario: oldObj.[...someArray] - a very narrow use case.

When a certain task is common enough, it can be nice to have a little shortcut. Just like the newer ** operator is just a shortcut for Math.pow()

1 Like
// pick a, b, and c off
// if b doesn't exist, set it to 2
// rename c to C
const newObj = oldObj.{ a, b = 2, c: C }

If b doesn't exist, it should not be picked off. It seems like another meaning like "restructuring"?

Sorry, my comment wasn't very clear. If it was more explicit, it would have said "if b does not exist on oldObj, set b to 2 on newObj`

Does that clear up your concern? Or is that how you were already understanding it?

The idea of supporting renaming and providing default values was just an additional idea to go on top of this pick syntax. It's certainly not a necessary piece, just a nice bonus.

(and yes, and the other thread, I had called it "restructuring syntax", because it gave you the ability to restructure objects in different ways. The primary type of restructuring it supported was being able to pick values off an object. Everything else was just extra nice-to-haves)

Yes, but it has violated the motivation of the proposal, which hopes to introduce a way to pick off something from an existing object. If hoping it works like restructuring, it may be another new proposal to bring out the idea.

I think there's something that's not getting communicated very clearly here.

  • The "rename" addon just lets you rename a value as you're picking it
  • The "default value" addon just lets you use a default value if there was nothing available to be picked.

Both of these addons are very much related to picking. They never modify the original object. I just chose to call it restructuring in that proposal, but I could have named the proposal "pick syntax" (I almost did), and it would have been just as meaningful of a name.

But let's ignore the "default assignment" and "renaming" addons for now - those aren't necessary anyways, just nice-to-haves that might not actually happen.

What we're left with is literally just a pick syntax. The exact same as @jamiebuilds proposed, and really not any different than what you're proposing, it just looks a little different, but functions the same.

const oldObj = { a: 1, b: 2, c: 3 }

// this
console.log(oldObj.{ a, b }) // { a: 1, b: 2 }

// is the same as this
console.log(oldObj.['a', 'b']) // { a: 1, b: 2 }

// this (if we support dynamic keys)
oldObj.{ [dynamicKey] }

// is the same as this
oldObj.[dynamicKey]

// this (if we support dynamic keys)
oldObj.{ ...keys }

// is the same as this
oldObj.[...keys]

Quick question:

let o = { x: undefined };
let n = o.{ x, y };
n.hasOwnProperty('x'); // -> true
n.hasOwnProperty('y'); // -> ???

From a pick method I would expect false β€” i.e. don't create new keys that weren't on the original, unless I explicitly defaulted them. Notably, it would be different from:

let oxy = { x: o.x, y: o.y };

I was simply pointing out an issue with o.[comma,separated,list], and offered an alternative o[...[comma,separated,list]]. I don't like either of those, there's reasonably concise syntax for that already (provided the method exists): Object.pick(o, [comma,separated,list]) or Object.pick(o, comma, separated, list).

It is a vision around picking and thanks for sharing ideas, @jamiebuilds @theScottyJam @lightmare . I have noted under current proposal: GitHub - aleen42/proposal-object-pick-or-omit: Introduce `Object.{pick,omit}` for operating properties of objects more conveniently.

Welcome to discuss it.

1 Like

That's something I haven't thought about much @lightmare, but it's a good question. I think you're right, if a value does not exist on the old object, then it won't be picked and placed on the new object, so n.hasOwnProperty('y') should be false.

@aleen42

  1. error model design
    i want based GitHub - tc39/proposal-error-cause: TC39 proposal for accumulating errors design

  2. __proto__ is deprecated feature.
    plz do not support it, thanks
    see Object.prototype.__proto__ - JavaScript | MDN

@septs

For point 1, are you suggesting that, for example, when picking properties off of an object, and a getter is triggered that throws an error, the pick function should instead throw some sort of "Failed to pick" error, with its cause set to the original error?

Point 2 seems like a good idea

1 Like

The first point seems like a good suggestion, but it seems that the traces has apparently show why the error is thrown?

Uncaught Error
    at Object.get (<anonymous>:2:20)
    at Object.pick (<anonymous>:2:10)
    at <anonymous>:1:8 

I agree with the second point, and I will update the proposal document later.

Hang on - __proto__ is deprecated, but it's also just a simple getter/setter on Object.prototype. What does it mean to not support "__proto__"? If we find the string "__proto__" in the list of things we want to pick off of the provided object, we then check to see if passedInObj.__proto__ refers to the getter/setter on Object.prototype and if so, throw an error? Why add special logic for __proto__ and not other deprecated features, like Object.prototype.__defineGetter__()?

2 Likes

@septs Like what @theScottyJam has said, it seems that a proposal should not take care of deprecated things, and it should be pure enough to just describe whether the prototype should be picked or not. If it should be, deprecated things should become invalid once they have been removed.

3 Likes

@theScottyJam Had the same idea

I've seen multiple people independently come up with this same idea now - it shows that it must be a pretty intuitive idea :)

2 Likes

If Object.pick takes only own properties, then pick & remove might also be useful:

b = Object.pluck(a, 'x', 'y');

roughly equiv to:

b = Object.pick(a, 'x', 'y');
delete a['x'];
delete a['y'];

That can be done using the current proposal as follows:

b = Object.pick(a, 'x', 'y')
a = Object.omit(a, 'x', 'y')

// alternativly

b = Object.pick(a, 'x', 'y')
a = Object.omit(a, ...Object.keys(b))

If we were to add such a method, I would prefer that it acted more like a "partition" and returned two new objects instead of modifying the source object. But I'm happy just doing two separate method calls for this use case.

No it can't, I actually want to pick & remove from the original.
If I wanted a copy, I'd do b = Object.pluck(a = { ...a }, 'x', 'y')

Within current prooosal, you can:

const pluck = (obj, keys) => {
    const picked = Object.pick(obj, keys);
    keys.forEach(key => { delete obj[key] });
    return picked;
};

Sorry, @theScottyJam I have edited the example.