14

Is there a way to destructure an object in JavaScript and alias the local destructured object?

Something like:

const env = {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env;

...and have env become a local constant containing those selected environment variables. (I'm aware that my example doesn't work with babel)

{
  ENV_VAR_X: "s867c7dsj4lal7", 
  ENV_VAR_Y: "hd73m20s-a=snf77f", 
  ENV_VAR_Z: "production"
}

Is there a way to achieve this aliasing?

On a side note, I'm using babel as my transpiler, then running the script with node so that I can leverage more ECMAScript 6 functionality.

Seth
  • 9,056
  • 9
  • 40
  • 67
  • Works for me in FF Nightly.. https://gist.github.com/liam4/393863561cb20e1b90b0 – Florrie Feb 21 '16 at 03:04
  • That's awesome and unfortunate at the same time! Using babel6, it doesn't though :( I'd like an example to target that. – Seth Feb 21 '16 at 03:05
  • I'm not sure that's really possible with destructuring until babel fixes that.. :( – Florrie Feb 21 '16 at 03:08
  • It also doesn't work with node latest :( Looks like I'll have to take the verbose route. – Seth Feb 21 '16 at 03:20
  • Also works with Chrome canary :| – Seth Feb 21 '16 at 03:22
  • Sadly an invalid left side assignment using `node --harmony_destructuring` :i – Florrie Feb 21 '16 at 03:24
  • 1
    I've added a feature request to babel's issue tracker. Hopefully it can be fixed soon enough. There's no only way to achieve this without essentially writing a double assignment, one for the destructured object and one for the aliased object? – Seth Feb 21 '16 at 03:30
  • It sounds so. Great that an issue is being tracked now though. – Florrie Feb 21 '16 at 03:30
  • https://phabricator.babeljs.io/T7130 – Seth Feb 21 '16 at 03:32
  • Can you point to the relevant portion of the spec which defines what this is supposed to mean? –  Feb 21 '16 at 04:48
  • I'm not certain if it's part of the spec. I did not read the white papers regarding destructuring. However, I am wondering if/how this can be accomplished. – Seth Feb 21 '16 at 05:15
  • This is an incorrect duplicate. This question should be re-opened. –  Jul 13 '16 at 16:09

1 Answers1

14

According to my reading of the spec, this should be parseable, but it doesn't mean what you think. It would be parsed from right-to-left as

const env = ({ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env);

where the production

({ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env)

is defined, like all other assignments, as evaluating to the RHS, which is process.env.

Therefore, your code is equivalent to

const {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env;
const env = process.env;

It's quite easy to validate this:

const foo = {a: 1, b: 2};
const bar = {a} = foo;

results in a new constant a being declared with the value 1, as you would expect. However, the value of bar is not an "alias to the deconstructed object", which would be {a: 1}; it's the same as foo, which is {a: 1, b: 2}. bar === foo.


What you are trying to do has been discussed many times here on SO and also in the ES discuss group. The bottom line is that there is no way to do this. All you can do is:

const {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env;
const env = {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z};

In other words, there is no way to "deconstruct from an object into an object", or "pick from an object into an object". You can only deconstruct from an object into variables.

You could fall back to the old-fashioned way:

const env = {ENV_VAR_X: process.env.ENV_VAR_X, ...

which I know is horrible.

You could use the pick function from underscore or write your own, but that requires you to say

const env = _.pick(process.env, 'ENV_VAR_X', "ENV_VAR_Y', 'ENV_VAR_Z');

which is only slightly less horrible.

We have "rest properties" and "spread properties" proposed for ES7, but they do not seem to help us here.


What we need is a new syntax for picking properties into another object. There have been various proposals made for this, none of which has gained much traction. One is the "extended dot notation", which allows a curly-bracketed construct to be put after a dot. In your case, you would write

const env = process.env.{ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z};
                       ^^

You can find out more about this proposal here.

Carsten Führmann
  • 2,102
  • 3
  • 23
  • 20
  • Gotcha. So this is not possible at all? My only option is to either a) deal with the entire object being assigned to the local variable `bar`, or b) define a new variable containing the desired properties from the target object? – Seth Feb 21 '16 at 05:22
  • "results in a new constant `a` being declared with the value 1," --- `a` would not be declared, since there is no declaration for it in that statement. – zerkms Feb 21 '16 at 05:39
  • Dangerous error at "Therefore, your code is equivalent to […]": the `ENV_VAR_*` variables become global, not `const`. Proof: `(function() { const a = {x} = {x: 1}; })(); console.log(window.a === undefined && window.x === 1); // true`. – wchargin May 09 '18 at 23:32