# Array.prototype.keyMap

**URL:** https://es.discourse.group/t/array-prototype-keymap/1950
**Category:** 💡 Ideas
**Tags:** proposal, iterator-helpers
**Created:** [March 14, 2024, 2:00am UTC](https://es.discourse.group/t/array-prototype-keymap/1950 "2024-03-14T02:00:30Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![brandonmcconnell](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/brandonmcconnell/32/2395_2.png) [@brandonmcconnell](https://es.discourse.group/u/brandonmcconnell)
#### Post date: [March 14, 2024, 2:00am UTC](https://es.discourse.group/t/array-prototype-keymap/1950/1 "2024-03-14T02:00:30Z")

</div>

I've noticed a common pattern that I think could stand to be simplified.

```js
  const labels = {
    type1: 'Type 1',
    type2: 'Type 2',
    type3: 'Type 3',
  };

  const descriptions = {
    type1: 'Type 1 Description',
    type2: 'Type 2 Description',
    type3: 'Type 3 Description',
  };
  
  // assume that this `type` variable updates reactively
  let type = 'type3';
  const [label, description] = [labels, descriptions].map(obj => obj[type]);

```

I found myself doing this quite a bit, where I had to access a certain key from each of the objects in an array. What if we had something like `keyMap(key)` method for arrays, that allowed you to get the value for that key in several objects at once? It's not hard as it is, but it would certainly streanline the process a bit. For example:

```js
const [label, description] = [labels, descriptions].keyMap(type);

// or

[[1, 2, 3], [4, 5, 6], [7, 8, 9]].keyMap(1) // [2, 5, 8]

```

The implementation could be something like this:

```js
Array.prototype.keyMap = function(key) {
  return this.map(obj => obj[key]);
}

```

So with this, you'd get either the value at the key, or `undefined` if the key isn't there.

---

<div class="post-metadata">

### Author: ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)
#### Post date: [March 14, 2024, 2:44am UTC](https://es.discourse.group/t/array-prototype-keymap/1950/2 "2024-03-14T02:44:23Z")

</div>

For your particular case,

> [@brandonmcconnell](#):
>
> ```
> const [label, description] = [labels, descriptions].map(obj => obj[type]);
> const [label, description] = [labels, descriptions].keyMap(type);
> 
> ```

it would be simpler and shorter to write

```
const label = labels[type], description = descriptions[type];

```

For the general case, an array method is far too specifc. For better composability, this should be an `Object` method to create a property accessor function:

```javascript
[1, 2, 3], [4, 5, 6], [7, 8, 9]].map(Object.get(1)) // [2, 5, 8]

```

with

```javascript
Object.get = key => obj => obj[key];

```

---

<div class="post-metadata">

### Author: ![brandonmcconnell](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/brandonmcconnell/32/2395_2.png) [@brandonmcconnell](https://es.discourse.group/u/brandonmcconnell)
#### Post date: [March 14, 2024, 10:37am UTC](https://es.discourse.group/t/array-prototype-keymap/1950/3 "2024-03-14T10:37:20Z")

</div>

@bergus An `Object.prototytpe` method like that might be confusing to users, as I would generally assume an `Object.get()` method to do something like this:

```js
Object.get({ a: 1 }, 'a') // 1

```

That said, if that's not a valid a concern, I think your idea of `.map(Object.get(key))` would work extremely well for this, except that it's actually longer-form.

```js
[[1, 2, 3], [4, 5, 6]].map(Object.get(1))
[[1, 2, 3], [4, 5, 6]].map(o => o[1])

```

What of we used a new syntax (and I don't think this is valid syntax currently, so hopefully no conflicts):

```js
let key;

key = 'a'
[{ a: 1, b: 2 }, { a: 3, b: 4 }].map([type]) // [1, 3]

key = 'b'
[{ a: 1, b: 2 }, { a: 3, b: 4 }].map([type]) // [2, 4]

[{ test1: 1, test2: 2 }, { test3: 3, test4: 4 }].map(['test2']) // [2, undefined]

[[1, 2, 3], [4, 5, 6]].map([1]) // [2, 5]

```

Both of these appear to produce an error currently, as you'd expected. This would introduce new support for destructuring a key directly as the map's return value, instead of passing a callback.

This way, no new method would be required, instead building upon the usage of `Array.prototype.map`

This same new syntax could have implications for other array methods as well and be beneficial in their cases as well.

For example, in the case of `Array.prototype.filter`, you might typically write something like this:

```js
const stores = [
  { id: 1, city: 'Test 1', open: false },
  { id: 2, city: 'Test 2', open: true }
];

const openStores = stores.filter(store => store.open)
// or
const openStores = stores.filter({ open } => open)

```

With this new method, you could check the key without needing to use a redundant parameter like this, while retaining the same level of type safety and narrowing:

```js
const openStores = stores.filter(['open'])

```

This would be equally helpful for use with other methods like `find`, `findLast`, `findIndex`, `findLastIndex`, `some`, `every`, etc.), an example might look like this. For example:

```javascript
const stores = [
  { id: 1, city: 'Test 1', closed: false },
  { id: 2, city: 'Test 2', closed: true }
];
const someStoresOpen = stores.some(['open']);
const noStoresOpen = !stores.some(['open']);
const allStoresOpen = stores.every(['open']);
const notAllStoresOpen = !stores.every(['open']);

```

---

<div class="post-metadata">

### Author: ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)
#### Post date: [March 14, 2024, 4:39pm UTC](https://es.discourse.group/t/array-prototype-keymap/1950/4 "2024-03-14T16:39:54Z")

</div>

Given that `[[1, 2, 3], [4, 5, 6]].map(o => o[1])` is not hard to get right, slow, unclear, inconvenient, or a common need, why would it make sense to add anything to the language for this, especially syntax (the most expensive thing)?

---

<div class="post-metadata">

### Author: ![brandonmcconnell](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/brandonmcconnell/32/2395_2.png) [@brandonmcconnell](https://es.discourse.group/u/brandonmcconnell)
#### Post date: [March 14, 2024, 7:40pm UTC](https://es.discourse.group/t/array-prototype-keymap/1950/5 "2024-03-14T19:40:15Z")

</div>

@ljharb `reduce` isn't too hard to get right, though I believe there was still benefit in adding `map`:

```js
[[1, 2, 3], [4, 5, 6]].reduce((a, x) => [...a, x[1]], [])
[[1, 2, 3], [4, 5, 6]].map(x => x[1])
[[1, 2, 3], [4, 5, 6]].keyMap(1)

```

I agree that new syntax is expensive, and honestly, I think the new syntax I showed above would be more confusing than not.

I do believe a new method would be simpler, and would bring a quality of life benefit to the dev community as I and many other devs use this pattern a ton

Our codebases begin to feel like this:

```js
[user0, user1, user2].map((user) => user.name)
[data0, data1, data2].map((data) => obj.created_at)
[event0, event1, event2].map((event) => obj.datetime)
// and so on, often several times in the same module

```

As you said, the existing implementation using **`Array.prototype.map`** is not bad, though I think this would be a very welcome change and improvement in cases like this.

The above examples would become:

```js
[user0, user1, user2].keyMap('name')
[data0, data1, data2].keyMap('created_at')
[event0, event1, event2].keyMap('datetime')

```

If we were to introduce new syntax, I would probably disregard my earlier proposal of the `([…])` syntax, as I think that would cause tons of confusion, and in that case, **`Array.prototype.map`** would simply accept valid key types (e.g. string, number, symbol), in which case those would become:

```js
[user0, user1, user2].map('name')
[data0, data1, data2].map('created_at')
[event0, event1, event2].map('datetime')

```

---

<div class="post-metadata">

### Author: ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)
#### Post date: [March 14, 2024, 8:31pm UTC](https://es.discourse.group/t/array-prototype-keymap/1950/6 "2024-03-14T20:31:10Z")

</div>

Empirically i think reduce is exceedingly hard to get right :-)
