There seems to be a common desire for a shorthand to create an object by picking properties off of another object. Here are a few proposals other users have brought up on this forum:
-
This proposal for syntax as follows:
const { a, b } as newObj = oldObj
-
This proposed object literal shortand syntax:
const newObj = { oldObj.a, oldObj.b }
- One person proposed syntax for yielding only specific properties from an object.
- A proposed
Object.pick()
function.
I'd like to add to this conversation by proposing an "object restructuring" syntax, that can provide this kind of desired behavior. This syntax is inspired by the Bosque programming language's Bulk Algebraic Operations and works as follows:
const user = {
firstNamem: 'Spider',
lastName: 'Man',
city: 'New York',
street: 'Walnut Street'
}
const address = user.{ city, street, state }
console.log(address) // { city: 'New York', street: 'Walnut Street', state: undefined }
We could additionally provide syntax similar to object destructuring, to allow renaming properties and providing default values. This fits well with syntax that javascript already has, but isn't a necessary part of this proposal.
const address = user.{ city: someCity, street = 'UNKNOWN', state = 'UNKNOWN' }
console.log(nameAttributes) // { someCity: 'New York', street: 'Walnut Street', state: 'UNKNOWN' }
Some example use cases for this syntax:
const createUser = opts => Object.freeze(
opts.{ firstName, lastName, city, state, street, zipCode }
)
async function performQuery(params) {
const { allowEmpty = true } = params
const query = params.{ selectAttributes: select, whereCondition: where, tableName: table }
const paging = params.{ limit = 0, offset: start = 0 }
const entries = await database.query({ query, paging })
if (entries.length === 0 && !allowEmpty) throw new Error('Query Failed!')
return entries
}
Rational behind this syntax
There are a couple of alternative ways to achieve a similar idea in the language, but they don't scale well when there's a lot of properties being extracted.
Lets take the most straight-forwards approach:
const extractQueryParams = params => ({
select: params.select,
where: params.where,
table: params.table,
allowEmpty: params.allowEmpty,
limit: params.limit,
start: params.offset,
ordering: params.ordering,
orderBy: params.orderBy,
})
Did you notice that one of those parameters got renamed in this function? Its difficult to tell. Someone who wants to make it abundantly clear which properties are getting renamed, if any, might choose to destructure, then recreate the object from locals, like in this example:
async function performAnotherQuery(params) {
const { select, where, table, allowEmpty, limit, offset, ordering, orderBy } = params
const queryOptions = { select, where, table, limit: start, offset, ordering, orderBy }
const entries = await database.query(queryOptions)
if (entries.length === 0 && !allowEmpty) throw new Error('Query Failed!')
return entries
}
However, this approach has its own issues. Can you spot which destructured properties are not being used to create the new object? It's also pretty gross that we're polluting this function with so many local variables.
As shown before, this kind of feature request seems to keep cropping up with different syntaxes or styles, so I hope one of these feature requests gains some traction. I just thought I would throw another syntax into the conversation that I find to be intuitive, and wanted to know what other people's thoughts were on the matter.