5

Is there any way to destructure an object and assign its properties into an array rather than as variables? For example:

const obj = { a: 1, b: 2 };

const { a, b } = obj;
const arr = [a, b];

This works, but it requires restating the variables as the array values.

I have tried:

const arr = [(const { a, b } = obj)];

but this is a syntax error.

I had a similar idea with Object.values as in

const arr = Object.values((const { red } = chalk));`

...but this has the same issue of not being able to do destructuring in expressions.

Explosion Pills
  • 176,581
  • 46
  • 285
  • 363
  • 1
    Is there a reason not to just use `[obj.a, obj.b]` ? – Titian Cernicova-Dragomir Feb 09 '18 at 15:59
  • @TitianCernicova-Dragomir yes that will work fine, but then I have to type `obj.` a lot if I have a lot of properties to destructure. – Explosion Pills Feb 09 '18 at 16:05
  • In the second example you only have one property `const arr = Object.values((const { red } = chalk));` why not `const arr = Object.values(chalk.red)`? – Yury Tarabanko Feb 09 '18 at 16:07
  • but, do you want to add every property alone the object or like [{a: 1, b : 2}] – Kenry Sanchez Feb 09 '18 at 16:08
  • FWIW you can make your original code a *little* more terse: `const { a, b } = obj, arr = [ a, b ];`. You still have to type the names twice, though, and it still introduces two new variables into the local scope. – Jordan Running Feb 09 '18 at 16:10
  • As of the first the problem is that the order of properties is not guaranteed. So if there were a syntax to desctruct object to array w/o introducing intermediate variables how would you know the resulting order `[obj.a, obj.b]` vs `[obj.b, obj.a]` – Yury Tarabanko Feb 09 '18 at 16:11
  • You can just use [the `with` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with), oh never mind, nobody is allowed to use that anymore. – jcalz Feb 09 '18 at 16:12
  • @YuryTarabanko It's my understanding that OP is imagining some syntax where you would specify the names of the properties in the order you want, e.g. `const arr[ b, a ] = { a: 1, b: 2 };`. – Jordan Running Feb 09 '18 at 16:14
  • you can do this `[{ a, b} = obj]` but that is the problem of destructuring assignment, it will add to the array an object and not every property as a single – Kenry Sanchez Feb 09 '18 at 16:16
  • Ha, you could use default value `const {a, b, arr = [a,b] } = obj`. But if there is `obj.arr` it'll pick the latter. – Yury Tarabanko Feb 09 '18 at 16:23

4 Answers4

3

Is there any way to destructure an object and assign its properties into an array rather than as variables?

You can do

const arr = [];
const { a: arr[0], b: arr[1] } = obj;

but I think what you are really looking for is the equivalent to One-liner to take some properties from object in ES 6 which with an array literal would be

const arr = (({a, b}) => [a, b])(obj);
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
2

Really the answer you want is to go back in time and use the with statement before it was (rightly) recognized as evil:

var obj = { a: 1, b: 2 };
var arr;
with (obj) {
   arr = [a, b];
}

Any modern answer is going to require more typing than you'd like. A relatively type-safe answer that gets you closer is to use string literals. Stick this in a library:

function arrayDestruct<T, K extends keyof T>(obj:T, ...keys: K[]): T[K][] {
  return keys.map(k => obj[k]);
}

And then use it:

const arr = arrayDestruct(obj, 'a', 'b'); // recognized as number[]

You have to type some quotation marks but it works. It could even be overloaded to produce tuples, but I don't know if you really care enough. Anyway, good luck!

jcalz
  • 125,133
  • 11
  • 145
  • 170
0

You can't achieve that in one hit with destructuring. You have to have one extra line of code.

You can use Object.values, but not without losing type fidelity (i.e. you end up with an Array<any>.

interface ObjectConstructor {
    values(obj: {}): any[];
}

const obj = { a: 1, b: 2 };

// Array<any>
const arr = Object.values(obj);

// [1, 2]
console.log(arr);

So you have a trade off. One line of code in exchange for correct type information seems like the economic win.

const obj = { a: 1, b: 2 };
const { a, b } = obj;

// Array<number>
const arr = [a, b];

// [1, 2]
console.log(arr);
Fenton
  • 206,497
  • 63
  • 356
  • 369
-1

You can desconstruct the object like this

const [a, b] = Object.values(obj);

console.log(a); // 1
console.log(b); // 2

Remember that the keys of the object is not alphabetical, so its perhaps better to create a function which returns the sorted keys, so that you know that the values are set correctly.

function deconstructObject(obj){
    const arr = [];  
    const keys = Object.keys(obj);
    const sortedKeys = keys.sort();
        for(const key of sortedKeys){
            arr.push(obj[key]);
        }
        return arr;
}

const [a, b] = deconstructObject({b: 2, a: 1 });

console.log(a); // 1
console.log(b); // 2

const newArray = deconstructObject({b: 2, a: 1 });
console.log(newArray); //[1,2]

Now the object will be sorted, so you can predict its behaviour.

Pavlo
  • 1,057
  • 6
  • 13
  • he wants to use the destructing assignment as a single process. you're not using it. you are using a loop and give it an increase in the complexity... `O(n^2)` – Kenry Sanchez Feb 09 '18 at 16:18