Is there a way to do object destructuring with …rest in Javascript where the non-rest keys are dynamic?

Say I have an object:

const obj = { key1: "value1", key2: "value2", key3: "value3", key4: "value4" };

and I want to filter its keys to produce a smaller object. I understand I can do this:

const { key1, key2, ...rest } = obj;

And the rest variable will then be set to { key3: "value3", key4: "value4" }.

But can a similar thing be done dynamically without key1 and key2 being hard-coded? Let’s say they are in an array unwantedKeys, whose value (["key1", "key2"]) and length can only be determined at runtime.

>Solution :

But can a similar thing be done dynamically without key1 and key2 being hard-coded? Let’s say they are in an array unwantedKeys, whose value (["key1", "key2"]) can only be determined at runtime.

Yes, but not entirely dynamically. You’d need to know how many there were. For instance, for two of them:

const { [unwantedKeys[0]]: unused1, [unwantedKeys[1]]: unused2, ...rest } = obj;
const unwantedKeys = ["key1", "key2"];
const obj = { key1: "value1", key2: "value2", key3: "value3", key4: "value4" };
const { [unwantedKeys[0]]: unused1, [unwantedKeys[1]]: unused2, ...rest } = obj;
console.log(rest);

…which probably means it’s not useful for your situation. 🙂 (Edit: You’ve now confirmed that indeed, the length is only known at runtime.)

Since you need it to be dynamic, you can’t just do this with syntax; you can with various standard library tools, though, like:

const rest = Object.fromEntries(
    Object.entries(obj).filter(([key]) => !unwanted.includes(key))
);
const unwantedKeys = ["key1", "key2"];
const obj = { key1: "value1", key2: "value2", key3: "value3", key4: "value4" };
const rest = Object.fromEntries(
    Object.entries(obj).filter(([key]) => !unwantedKeys.includes(key))
);
console.log(rest);

Or perhaps with a Set, if unwantedKeys is so massively long that rescanning it is a performance concern (not likely 🙂 ):

const unwantedSet = new Set(unwantedKeys);
const rest = Object.fromEntries(
    Object.entries(obj).filter(([key]) => !unwantedSet.has(key))
);
const unwantedKeys = ["key1", "key2"];
const obj = { key1: "value1", key2: "value2", key3: "value3", key4: "value4" };
const unwantedSet = new Set(unwantedKeys);
const rest = Object.fromEntries(
    Object.entries(obj).filter(([key]) => !unwantedSet.has(key))
);
console.log(rest);

Leave a Reply