I want to define some object so that every property provides an empty array if it's not defined.
Example: consider the list of users, every user is {id: number, age: string, ...}
. We want to group users by age:
const users = [{id: 1, age: 42}, {id: 2, age: 42}, {id: 3, age: 43}]
const usersByAge = users.reduce((out, user) => {
if (!out.hasOwnProperty(user.age)) {
out[user.age] = []
}
out[user.age].push(user)
return out
}, {})
console.log(usersByAge[42]) -> [{id: 1, age: 42}, {id: 2, age: 42}]
console.log(usersByAge[43]) -> [{id: 3, age: 43}]
console.log(usersByAge[18]) -> undefined
console.log(Object.keys(usersByAge)) -> ['42', '43']
This code works, but I want to shorten it by using special JavaScript Proxy. It should return an empty array if the property is not defined. It should be possible to push items into the property even if it's not defined. It should provide the same array for different undefined properties:
const getMapFromIdToArray = () => {
return new Proxy({}, {
get: (target, name) => {
if (!target.hasOwnProperty(name)) {
target[name] = []
}
return target[name]
}
})
}
const usersByAge = users.reduce((out, user) => {
out[user.age].push(user) // <- this should work, array initialization should not be required
return out
}, getMapFromIdToArray())
console.log(usersByAge[42]) -> [{id: 1, age: 42}, {id: 2, age: 42}] - OK
console.log(usersByAge[18]) -> [] - OK
console.log(usersByAge[18] === usersByAge[19]) -> true - FAIL
console.log(Object.keys(usersByAge)) -> ['42', '43'] - FAIL
This code works partly. If the property is not defined, it's initialized as []. So the getter actually mutates the target. I would like to avoid this. But the same time I want to be able to call .push on an undefined property without initialization. Is it possible to achieve?