The minus operator: a spread operator enhancement proposal

Hey folks,

I've figured out a potential improvement for the object spread syntax and want to share my thoughts.
I've drafted my thoughts into a proposal available here: https://github.com/devlato/proposal-plus-minus-spread

Long story short, I want to propose a new minus operator, that would allow specify keys to remove the values from a result of object spread. It would look like this:

const result = {
 ...objA,
 ...objB,
 -keyToRemove,
};

// Or like this – the same result!
const result = {
 ...objA,
 -keyToRemove,
 ...objB,
};

// And this!
const result = {
 -keyToRemove,
 ...objA,
 ...objB,
};

What do you folks think?

Warmest regards,
Denis

1 Like

What if you wanted the key from the first one but not the second one? What happens if you minus a key that’s defined as a literal in the same object (above, or below)? Seems confusing to me.

Hey Jacob,

thanks for your question. The point is that if you want to remove the key from the result of the spread operator, the order doesn't matter – please have a look at the 'Execution order' section of explanatory doc (https://github.com/devlato/proposal-plus-minus-spread#execution-order).

Let me illustrate it with example. Let's consider you're merging two objects using a spread operator, and you want to remove the key 'test' from the result. There are four possible scenarios:

  1. The first object has the key 'test' and the second one doesn't.

  2. The first object doesn't have the key 'test' and the second one does.

  3. Both objects have key 'test'.

  4. Neither of the objects being merged have the key 'test'.

The point if that all the four scenatios are the same from a perspective of removing a key from the result. It doesn't matter what object the key comes from, as long as it's always possible to remove the key from the result, if it exists.

Basically, minus operator I'm proposing is a short form of writing this:


const r = {

...obj1,

...obj2,

};

delete t.keyToRemove;

const result = r;

Instead of the comparatively long and imperative-styled code above, you could write just:


const r = {

...obj1,

...obj2,

-keyToRemove,

};

or even:


const r = {

-keyToRemove,

...obj1,

...obj2,

};

as for the minus operator, its position in the spread operator body doesn't really matter.

I hope this answers your question.

Warmest regards,

Denis

Not a fan of order independence, especially considering that testOne below has foo: "bar" and testTwo below has foo: "replaced". It's inconsistent otherwise.

const one = {test: "test"}
const two = {foo: "bar"}

const testOne = {
    ...one,
    foo: "replaced",
    ...two,
}

const testTwo = {
    ...one,
    ...two,
    foo: "replaced",
}

Also, have you considered delete key instead of -key? That would be more consistent with the rest of the language in terms of property manipulation, since procedural property removal would be delete object[prop]/delete object.prop.

There was actually a need for this in Record and Tuples' deep properties. You can see a bit of the discussion in https://github.com/tc39/notes/blob/af7d3c84524579e124649b1df891503e19b1d0ea/meetings/2020-03/april-1.md#record-and-tuple-update, where we talk about deleting a prop from some deep record.

You might try discussing this on the R&T repo, since they'd be able to champion it.

1 Like

Thanks @jridgewell – I'll have a read and will try to chase them up :+1: