Optional keys in objects

Actually it doesn't matter what it has been. It's important what it will become. As an example take a look at decorators proposal history. To develop stronger standards different points of view should be reviewed. This is how research process works. So I honestly don't understand your intentions.

However, there wasn't just one decorator proposal, there were at least three that I know of. The original one that got rejected, and two later ones that attempt to replace the original one (one of which has also since been rejected I think). They didn't just reuse the old one to continue the discussion, in part because it's important to section of different types of conversation. While it's good to take into account a lot of different perspectives, it's common for proposal authors to simply say that X idea is out of the scope of the proposal they're trying to build, please discuss it elsewhere (it's still an important discussion to have, just not on that particular proposal).

So, there's a fair argument to trying to stay on topic with an original point while leaving side discussions to different threads.

But, @ramkin, if could you perhaps help show us a little more how your idea relates to the original issue of optionally adding single entries, then it would show how your idea relates.

You mentioned that Object.clean() is strictly more powerful than an optional key syntax. I'm not sure if that's true. What if you only want to clean individual keys, not the whole object? This thread seems to assume that this will be a common scenario. You mentioned that the object restructuring syntax can help - could you perhaps explain how you would use the object restructuring syntax in conjunction with Object.clean()?

I think a little more information in that regard could help show how this Object.clean() function can be used to solve the original use case of needing to optionally add a single key to an object.

Thanks for joining.

Well, why I think Object.clean is good for that? First of all, I think it can do whatever the syntax proposal can do, even remove individual properties (with help of additional arguments Object.clean(target, keys). As long as it's a function it's easier to implement and deliver this changes to developers and different environments. And it's possible to combine it with other Object's methods (assign, create, etc. and probably with omit and pick in the future). It's just a logical complement for object manipulation set of methods. This is how code from author's example can look:

function enrich(input, optionalData) {
  return Object.assign(
    {}, input, Object.clean({additionalKey: optionalData}, ['additionalKey'])
  )
}

// or

function enrich(input, optionalData) {
  return {
    ...input,
    ...Object.clean({optionalData}, ['optionalData'])
  }
} 

But what's more important it's unclear what should happen if there already is property additionalKey in the input object and both input.additionalKey and optionalData variable are nullish. Should the result object contain optionalKey property? Following the logic it should, but IMO it's not what author wants. For such expressions:

{
  ...{additionalKey: null},
  additionalKey?: undefined,
}

The resulting object should be {additionalKey: null}. So this syntax isn't solving issue of getting rid of top-level nullish values and developer still need to use something like Object.clean.

What's about syntax and object restructuring. I think syntactical changes are most potentially harmful, thus they need more attention by community. Also we have limited set of characters and their combinations, so we should use them carefully. Object restructuring is extremely powerful instrument and it can bring a lot of good to developers. I think it should contain as much operations over object structure as possible. And removing nullish values from objects intersection is one of such operations. This is why I think syntax change should became a part of the bigger proposal.

1 Like

This is a very interesting point. In the O.P.'s specific scenario, they mentioned that the optionalData object would be "additional keys", which implies nothing in optionalData should be masking anything in the input object, which also means they don't need to worry about the original data containing "additionalKey". I feel like this will be the scenario for most use cases, but still, this is an interesting point and a good one to discuss.

I can't think of any good concrete examples where this situation may happen, but if you can think of one, that would be helpful to further discuss this.

This is certainly true, and one of the reasons why there's a high bar for new syntax. This is also one of the reasons why I personally prefer the syntax I proposed earlier over here - I feel like it not only reads more naturally, but it'll also save us from using up our limited set of ascii characters.

const data = {
  x: 2
  y: if (condition) 3
}

const data = [
  2,
  if (condition) 3
]

It sounds like you're wanting to take that restructuring idea much further than I had ever imagined for it. It would be interesting to hear what you have in mind, if you ever want to spend the time thinking it through and formulating a proposal out of it. Monster proposals usually don't make it too far, especially monster syntax proposals, but still, the discussion around them can be interesting.

In particular, I'm not sure how you would incorporate "remove nullish" into that syntax. Would you do it as a single-property level? In this scenario, you'd probably end up with syntax that looks similar to what's being proposed here, but it's only available within object restucturing. If such a syntax got accepted within object restructuring, it should surely be possible to also provide this syntax for object literals as well. Or, would you try and clean the whole resulting object? If this is the case, would you also include the ability to name specific keys you want to poke at? If not, there would be use cases for the syntax proposed here that's not being covered. If so, well, I'm having difficulty envisioning how such a syntax would even look.


Let's try playing with a more concrete example, that's loosely inspired by something I've been working on. Say I'm trying to create a function that takes in form data and outputs an object of this shape.

{
  expirationDate: A date, or null
  sourceOrg: A string
  targetOrgs: Only present if targetAllOrgs is false, in which case, it's a list of strings.
  targetAllOrgs: A boolean
}

Here are some different ways to implement this.

// Original version (without any special syntax)
const recordFromFormFields = ({ expirationDate = null, source, targets, targetAll }) => ({
  expirationDate: expirationDate,
  sourceOrg: source,
  ...(targetAll ? {} : { targetOrgs: targets.split(', ') }),
  targetAllOrgs: targetAll,
})

//// ---- Other ways to implement that one line of code ---- ////

// Original, awkward-to-read solution already presented
...(targetAll ? {} : { targetOrgs: targets.split(', ') }),

// Alternative trickier solution that's also possible today
...(targetAll || { targetOrgs: targets.split(', ') }),

// Using the syntax originally proposed
targetOrgs?: targetAll ? undefined : targets.split(', '),

// Using the syntax I proposed
targetOrgs: if (!targetAll) targets.split(', '),

// Using your proposed function.
...Object.clean({ targetOrgs: targetAll ? undefined : targets.split(', ') })

// Using your proposed function on the whole object
// (It's not so bad, but it does unfortunetally puts the names of
// the keys being cleaned far from the physical location of those keys)
const recordFromFormFields = ({ expirationDate = null, source, targets, targetAll }) => Object.clean({
  expirationDate: expirationDate,
  sourceOrg: source,
  targetOrgs: targetAll ? undefined : targets.split(', '),
  targetAllOrgs: targetAll,
}, ['targetOrgs'])

Honestly, if we can't get new syntax in (highly likely), a solution like Object.clean() with a parameter to target specific keys would probably be the next best thing. It would still allow us to create object literals in an expression position, with optional keys, without doing the "awkward" or "tricky" stuff I mentioned earlier.

Well, don't forget about emptiness checks for computed keys. Object.clean function won't solve the case where a key itself may be given or not, which is the half part of the reason I want a dedicated syntax here.

Looks like a new proposal came around to solve exactly this issue! GitHub - bertyhell/object-assignment-null-properties: A proposal to introduce new shorthand assignment for ECMAScript object literals where the value is falsey/undefined/null

Stage: -1

Not sure if they're talking it in the right direction.

Oh, whoops. I had mis-read some stuff, and had assumed that it was at stage 0, and that the repo just hadn't been updated yet.

Shame. Hopefully either this proposal, or some proposal like it eventually comes around.