Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: pre-compile "obj{ a, b }" to "(({a,b})->{a,b})(obj)" to create a copy of "obj" with only properties "a" and "b" #5326

Open
eugene-piatenko opened this issue Jun 26, 2020 · 9 comments

Comments

@eugene-piatenko
Copy link

  1. It's feature request.

  2. Description:

    it's a very common pattern when you need to pickup only some properties from object
    and to do this people usually use such constructs:

Input Code

obj1 = a:1, b:2, c:3
obj2 = ( ({a,b}) -> {a,b} ) obj1

Possible Solution

would be nice to have an "operator" like this:

obj1 = a:1, b:2, c:3
obj2 = obj1{ a, b }

as we can do

obj1 = a:1, b:2, c:3
{ a, b } = obj1
obj2 = { a, b }

but it destruct local variables "a" and "b"
or

obj1 = a:1, b:2, c:3
obj2 = ( ({a,b}) -> {a,b} ) obj1

that way is safe but looks ugly )

Thank you!

@GeoffreyBooth
Copy link
Collaborator

It sounds like you're basically asking for the inverse of object spread, which creates a larger object (i.e. obj3 = { obj1..., d:4 }). I'm not sure there's a succinct way to do this currently. I've most often seen it done like this:

obj1 = a:1, b:2, c:3
obj2 =
  a: obj1.a
  b: obj1.b

It's a bit repetitive, but it avoids extra local variables. Or to get closer to your example, you can create a scope around the destructuring to isolate those variables:

obj1 = a:1, b:2, c:3
obj2 = do -> { a, b } = obj1; { a, b }
# obj2 is now {a:1, b:2}

See example.

@vendethiel
Copy link
Collaborator

See #4991 (and #1708, #1617).

@edemaine
Copy link
Contributor

edemaine commented Jun 27, 2020

I've run into this a bunch lately, and find it ineligant that all existing solutions need to repeat a and b at least twice.

A possible extension to destructuring I thought of that I was a bit surprised didn't work is the following:

obj1 = {a: 1, b: 2, c: 3}
obj2 = {}
{obj2.a, obj2.b} = obj1

Intended complication:

var obj1, obj2;
obj1 = {a: 1, b: 2, c: 3};
obj2 = {};
obj2.a = obj1.a
obj2.b = obj1.b

Do you think this would be interesting, or is it confusing notationally? It requires repeating obj2 a bunch, but at least not a and b.

Actually, now I realize @GeoffreyBooth's last example can be simplified to:

obj1 = {a: 1, b: 2, c: 3}
obj2 = do -> {a, b} = obj1

which it pretty nice: nothing repeated.

@eugene-piatenko
Copy link
Author

Unfortunately

obj1 = {a: 1, b: 2, c: 3}
obj2 = do -> {a, b} = obj1

does not work ((
it will return obj1 as this example also:

obj2 = {a, b} = obj1

But now I see a lot of people discussing it >> #4991 (and #1708, #1617).

@rdeforest
Copy link
Contributor

How about:

pick = (obj, keys...) ->
  if keys.length is 1 and Array.isArray keys[0]
    keys = keys[0]

  Object.assign {}, ([key]: obj[key] for key in keys)...

obj1 = a: 1, b: 2, c: 3
obj2 = pick obj1, 'a', 'b'

If you don't like the many quotes in 'a', 'b'...

qw = (s) -> s.split /\s+/ # like Perl's qw{} operator
obj2 = pick obj1, qw 'a b'

I'm not convinced the requested feature is justified.

@GeoffreyBooth
Copy link
Collaborator

How about:

https://lodash.com/docs/4.17.15#pick:

var object = { 'a': 1, 'b': '2', 'c': 3 };
 
_.pick(object, ['a', 'c']);
// => { 'a': 1, 'c': 3 }

@Inve1951
Copy link
Contributor

Inve1951 commented Jul 19, 2020

Here's another one: #try

pick = (cb) -> Reflect.apply cb, res = {}, []; res

obj1 = a:1, b:2, c:3
obj2 = pick ->
  { @a, @b } = obj1

I generally found Reflect patterns to be the most viable option for accessing several props since it lets you use the @prop shorthand. Though in this case I'd just copy-paste the property list/object to do something like @GeoffreyBooth suggested above:

obj2 = do ->
  { a, b } = obj1
  { a, b }

An unfortunate sideeffect of this pattern is that you have to pay attention to variable scope and are conditionally required to shadow your props:

a = "something else"
obj2 = do (a, b) ->  # ReferenceError: b is not defined
  { a, b } = obj1
  { a, b }

@JanMP
Copy link

JanMP commented Oct 18, 2020

The expression {a, b} = obj1 evaluates to obj1. That feels kind of wrong, since that line is doing something to obj1 and I would expect the expression to evaluate to the result and not the input of the operation.

If it did evaluate to the left side we could just write obj2 = {a, b} = obj1.

@Inve1951
Copy link
Contributor

The expression {a, b} = obj1 evaluates to obj1.

This is in alignment with JS' destructuring assignment and as such will unlikely change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants