0

I want to destructure a dynamic key from a object, where `key` is some pattern. There is counter appended to key.

var obj = {
 "key2":{"left":{"content": "This data to be pulled"}},
 "hasErrorcharges2":false,
 "hasErrorcharges2_Card":""
}
const {key2: {left: content }} = obj;

Here key2 is dynamic. So we know that it will always start with key and the other values can be key0, key1, key3 and hence forth. How do we traverse in this case?

Things tried.

  1. Match the if object has any key similar to it. and then return the matched key. but got true false

  2. can't destructure dynamic prop. but in this we know a pattern

  3. traverse through the object with dynamic property and get the value.

  4. expecting to write a similar function like hasOwn() or hasOwnProperty

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Ashish Singh Rawat
  • 1,419
  • 16
  • 30
  • 1
    If you don’t know the key in advance, you can’t use destructuring. Not sure what specifically you’ve tried, but get familiar with [how to access and process objects, arrays, or JSON](/q/11922383/4642212), and use the static and instance methods of [`Object`](//developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object#Static_methods) and [`Array`](//developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array#Static_methods). It looks like you can just use `find` and `startsWith` on the result of `Object.keys` or `Object.entries`. – Sebastian Simon Jan 16 '23 at 10:48
  • It is not entirely clear what target structure the OP wants the original data structure be transformed into, since the OP did not provide the expected result. Maybe the OP could get some ideas from the answer(s) of following question ... [_"How does one detect and access numbered property names like 'entry1', 'entry2'?"_](https://stackoverflow.com/questions/75077209/how-does-one-detect-and-access-numbered-property-names-like-entry1-entry2) – Peter Seliger Jan 16 '23 at 14:29

1 Answers1

2

You can't do the destructuring until you know the name of the property. You can find it by using find on Object.keys (but keep reading for an alternative). Then you can use computed property notation to specify that name in the destructuring expression. (There's also a small error in that expression, see the highlighted bit below.)

const keyName = Object.keys(obj).find((key) => key.startsWith("key"));
if (keyName) {
    const {
//      vvvvvvvvv−−−−−−−−−−−−−−−−−−−−−−−−−− computed property notation
        [keyName]: { left: { content } },
//                         ^−−−−−−−−−^−−−−− minor correction to destructuring
    } = obj;
    // ...
}

There I've just checked that the property name starts with key — you might want to beef up the condition in the find callback, but that's the general idea.

Live Example:

const obj = {
    key2: { left: { content: "This data to be pulled" } },
    hasErrorcharges2: false,
    hasErrorcharges2_Card: "",
};
const keyName = Object.keys(obj).find((key) => key.startsWith("key"));
if (keyName) {
    const {
        [keyName]: { left: { content } },
    } = obj;
    console.log(`content = ${content}`);
}

That said, if you need to loop through the object properties anyway, it may not be worth setting yourself up for destructuring vs. just grabbing the property in a loop and breaking when you find it:

let content = null;
for (const key in obj) {
    if (key.startsWith("key")) {
        content = obj[key].left.content;
        break;
    }
}
if (content !== null) { // Valid only if we know content won't be `null` in the object
    // ...
}

Live Example:

const obj = {
    key2: { left: { content: "This data to be pulled" } },
    hasErrorcharges2: false,
    hasErrorcharges2_Card: "",
};
let content = null;
for (const key in obj) {
    if (key.startsWith("key")) {
        content = obj[key].left.content;
        break;
    }
}
if (content !== null) { // Valid only if we know content won't be `null` in the object
    console.log(`content = ${content}`);
}

If you like, this:

content = obj[key].left.content;

could be:

({ content } = obj[key].left);

...which avoid repeating the identifier content. Or even:

({left: { content }} = obj[key]);

...though there's really no need to use the nested destructuring, it doesn't save you anything. :-)

(We need the () around it because otherwise the { at the beginning looks like the beginning of a block to the JavaScript parser.)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875