My data looks like this:

const sleepStages = [
  {deep: Array(40)},
  {light: Array(40)},
  {rem: Array(40)},
  {awake: Array(40)},

I'm using the key and values separately and am using TypeScript.

sleepStages.flatMap((sleepStage) => {
  const stageName = Object.keys(sleepStage)[0];
  const stageValues = Object.values(sleepStage)[0];
  console.log(stageName, stageValues);

Does this approach make sense? Whenever I type [0] it smells.

  • \$\begingroup\$ I can speculate that this is not the best way to store your data. However you haven't provided enough code for me to evolve this speculation into anything more. Right now I can think of plenty of different, potentially better or worse, solutions. As such I'm voting to close this as missing context. Whilst answerable, the answers you'll get will be sub-par. \$\endgroup\$ – Peilonrayz Apr 11 at 22:58
  • 2
    \$\begingroup\$ This seems like such a harsh criticism and result. What if the data is from an external API? That, and the answer by @CertainPerformance is specifically helpful along with a useful criticism of the data. 🤷‍♂️ \$\endgroup\$ – GollyJer Apr 12 at 0:00
  • 1
    \$\begingroup\$ If your data is coming from an API then your question is lacking a description at best, deceptive at worst. Either way it's off-topic. Closing a question that is off-topic is not harsh. \$\endgroup\$ – Peilonrayz Apr 12 at 0:04
  • 3
    \$\begingroup\$ Was just trying to keep things succinct. I'll do better next time. Thanks for the feedback. \$\endgroup\$ – GollyJer Apr 12 at 0:07
  • 1
    \$\begingroup\$ @GollyJer No, they wrote what they meant. \$\endgroup\$ – Peilonrayz Apr 13 at 12:58

A more concise approach would be to use Object.entries to get the 0th key and value at once:

const [stageName, stageValues] = Object.entries(sleepStage)[0];

Yes, the [0] looks weird, but unless you know the keys and/or in advance, you have to use a method which iterates over them, and then you need to extract the first item. In Javascript, there's no good way of avoiding the [0] - there's nothing like Object.prototype.getFirstEntry.

You could nest the destructuring on the left side, but that looks much less readable IMO:

const [[stageName, stageValues]] = Object.entries(sleepStage);

Ideally, in this sort of situation, you would fix the input data so that the keys are predictable and static:

const sleepStages = [
  { name: 'deep', values: Array(40) },
  { name: 'light', values: Array(40) },
  { name: 'rem', values: Array(40) },
  { name: 'awake', values: Array(40) },

Then, in the loop, you could do:

const { name, values } = sleepStage;
| improve this answer | |
  • \$\begingroup\$ +1 for the proposed structure improvement. Whenever there is a need to get an index like [0] on object keys or value, there is a better way of structuring the data, because object keys are by nature not guaranteed to be ordered. It also allows one of my favorite destructuring construct in modern javascript: for (const { name, values } of sleepStages) {}, where sleepStages: { name: string, values: any[] }[] \$\endgroup\$ – Christophe Marois Apr 11 at 22:49
  • 1
    \$\begingroup\$ Object property order is guaranteed, in all but pathological cases, as of ES2020, and has been effectively implemented in all implementations for years. Still, yeah, it's a code smell to rely on it. \$\endgroup\$ – CertainPerformance Apr 11 at 22:51
  • \$\begingroup\$ wow, good to know, thanks \$\endgroup\$ – Christophe Marois Apr 11 at 22:52
  • \$\begingroup\$ Thank you. This was super helpful. .entries wasn't on my radar until now. I'm using it for now and have asked our data team to update structure of the source data. 👍 \$\endgroup\$ – GollyJer Apr 12 at 0:06

Not the answer you're looking for? Browse other questions tagged or ask your own question.