Skip to content

Commit bfada8d

Browse files
authored
Bring back what has been accidentally left out
Bringing back dynamic keys
1 parent 9c8c511 commit bfada8d

File tree

1 file changed

+87
-96
lines changed

1 file changed

+87
-96
lines changed

README.md

Lines changed: 87 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -10,201 +10,192 @@
1010

1111
## Motivation
1212

13-
Since its introduction, the [object spread syntax](https://github.com/tc39/proposal-object-rest-spread) has become a cornerstone of modern JavaScript. Its declarative nature makes it highly readable and maintainable. However, current syntax falls short when developers need to exclude keys from objects, especially in complex use cases with multiple spreads.
13+
Since its introduction, the [object spread syntax](https://github.com/tc39/proposal-object-rest-spread) has become a cornerstone of modern JavaScript. Its declarative nature makes it highly readable and maintainable. However, current syntax falls short when developers need to exclude keys from objects, especially in complex use cases with dynamic keys or intermediate exclusions.
1414

1515
---
1616

1717
## Proposal
1818

1919
### Key Exclusion Syntax: `-key`
2020

21-
Introducing a concise, declarative way to exclude keys at any point in an object spread expression. The syntax dynamically removes the specified keys from all properties accumulated up to that point.
21+
The key exclusion syntax introduces a way to declaratively remove keys from objects during object spread operations. It works with:
22+
- **Static keys**
23+
- **Dynamic keys (e.g., values stored in variables)**
24+
- **Complex key expressions**
2225

2326
---
2427

2528
## Examples
2629

27-
### Basic Example: Key Exclusion at the End of Spread
28-
29-
The exclusion syntax can be used to remove keys from the final merged result:
30+
### 1. Excluding Static Keys
31+
The most basic use case, excluding specific keys directly in the spread syntax:
3032

3133
```js
32-
const sanitizedOpts = (opts) => ({
33-
...src,
34+
const sanitizedOpts = {
3435
...a,
36+
-key1,
3537
...b,
36-
-keyToExclude, // Removes 'keyToExclude' from the final merged result
37-
});
38+
-key2,
39+
};
3840
```
3941

40-
### Using Exclusion in the Middle of a Spread
41-
42-
The exclusion syntax can also be used in the middle of a spread expression, removing keys from the object as it is being built:
42+
### 2. Excluding Dynamic Keys (including Symbols)
43+
Dynamic keys, such as those stored in variables, can also be excluded:
4344

4445
```js
45-
const sanitizedOpts = (opts) => ({
46-
...src,
46+
const sanitizedOpts = {
4747
...a,
48-
-key1, // Removes 'key1' from { ...src, ...a }
49-
...b, // Spread 'b' after 'key1' is excluded
50-
});
48+
-[dynamicKey], // Excludes the value stored in `dynamicKey`
49+
...b,
50+
};
5151
```
5252

53-
### Multiple Exclusions at Different Points
53+
### 3. Excluding Multiple Keys Dynamically
54+
You can exclude an array of keys using the spread operator within the exclusion syntax:
5455

55-
Keys can be excluded multiple times at different points in the spread expression:
56+
```js
57+
const sanitizedOpts = {
58+
...a,
59+
-[...keysToExclude], // Excludes all keys in the `keysToExclude` array
60+
...b,
61+
};
62+
```
63+
64+
### 4. Using Complex Expressions as Keys
65+
Key expressions can be computed on-the-fly:
5666

5767
```js
58-
const sanitizedOpts = (opts) => ({
59-
...src,
60-
-key1, // Removes 'key1' from { ...src }
68+
const sanitizedOpts = {
6169
...a,
62-
-key2, // Removes 'key2' from { ...src, ...a }
70+
-[dynamicPrefix + "Id"], // Removes a computed key like "userId" if `dynamicPrefix` is "user"
6371
...b,
64-
});
72+
};
6573
```
6674

6775
---
6876

6977
## Behavior
7078

71-
### Desugaring Examples
79+
### Execution Order
80+
Key exclusions operate sequentially during object spreading. The syntax removes the specified keys from all properties accumulated **up to that point**.
7281

73-
#### Exclude Key at the End
74-
Input:
7582
```js
76-
const sanitizedOpts = (opts) => ({
83+
const sanitizedOpts = {
7784
...src,
7885
...a,
86+
-key1, // Removes 'key1' from { ...src, ...a }
7987
...b,
80-
-keyToExclude,
81-
});
82-
```
83-
Desugared:
84-
```js
85-
const sanitizedOpts = (opts) => {
86-
const _$1 = { ...src, ...a, ...b };
87-
delete _$1.keyToExclude;
88-
return _$1;
8988
};
9089
```
9190

92-
#### Exclude Key in the Middle
91+
### Desugaring Examples
92+
93+
#### 1. Excluding Static Keys
9394
Input:
9495
```js
95-
const sanitizedOpts = (opts) => ({
96+
const sanitizedOpts = {
9697
...src,
97-
...a,
9898
-key1,
99-
...b,
100-
});
99+
...a,
100+
};
101101
```
102102
Desugared:
103103
```js
104-
const sanitizedOpts = (opts) => {
105-
const _$1 = { ...src, ...a };
106-
delete _$1.key1;
107-
const _$2 = { ..._$1, ...b };
108-
return _$2;
109-
};
104+
const sanitizedOpts = (() => {
105+
const _$1 = {};
106+
for (const key in src) {
107+
if (key !== 'key1') _$1[key] = src[key];
108+
}
109+
for (const key in a) {
110+
_$1[key] = a[key];
111+
}
112+
return _$1;
113+
})();
110114
```
111115

112-
#### Multiple Exclusions at Different Points
116+
#### 2. Excluding Dynamic Keys
113117
Input:
114118
```js
115-
const sanitizedOpts = (opts) => ({
119+
const sanitizedOpts = {
116120
...src,
117-
-key1,
121+
-[dynamicKey],
118122
...a,
119-
-key2,
120-
...b,
121-
});
123+
};
122124
```
123125
Desugared:
124126
```js
125-
const sanitizedOpts = (opts) => {
126-
const _$1 = { ...src };
127-
delete _$1.key1;
128-
const _$2 = { ..._$1, ...a };
129-
delete _$2.key2;
130-
const _$3 = { ..._$2, ...b };
131-
return _$3;
132-
};
127+
const sanitizedOpts = (() => {
128+
const _$1 = {};
129+
for (const key in src) {
130+
if (key !== dynamicKey) _$1[key] = src[key];
131+
}
132+
for (const key in a) {
133+
_$1[key] = a[key];
134+
}
135+
return _$1;
136+
})();
133137
```
134138

135-
---
136-
137-
### Performance-Optimized Desugaring Example
138-
139-
For maximum performance, excluded keys can be omitted during the object-building process entirely, avoiding unnecessary copying or deletion.
140-
141-
#### Exclude Key Without Any Copying
139+
#### 3. Excluding Multiple Dynamic Keys
142140
Input:
143141
```js
144-
const sanitizedOpts = (opts) => ({
142+
const sanitizedOpts = {
145143
...src,
144+
-[...keysToExclude],
146145
...a,
147-
-key1,
148-
...b,
149-
});
146+
};
150147
```
151-
Optimized Desugared Code:
148+
Desugared:
152149
```js
153-
const sanitizedOpts = (opts) => {
150+
const sanitizedOpts = (() => {
154151
const _$1 = {};
155152
for (const key in src) {
156-
if (key !== 'key1') _$1[key] = src[key];
153+
if (!keysToExclude.includes(key)) _$1[key] = src[key];
157154
}
158155
for (const key in a) {
159-
if (key !== 'key1') _$1[key] = a[key];
160-
}
161-
for (const key in b) {
162-
_$1[key] = b[key]; // No exclusions here since key1 has already been removed
156+
_$1[key] = a[key];
163157
}
164158
return _$1;
165-
};
159+
})();
166160
```
167161

168-
#### Exclude Multiple Keys Without Any Copying
162+
#### 4. Using Complex Expressions
169163
Input:
170164
```js
171-
const sanitizedOpts = (opts) => ({
165+
const sanitizedOpts = {
172166
...src,
167+
-[dynamicPrefix + "Id"],
173168
...a,
174-
-[...keysToExclude],
175-
...b,
176-
});
169+
};
177170
```
178-
Optimized Desugared Code:
171+
Desugared:
179172
```js
180-
const sanitizedOpts = (opts) => {
173+
const sanitizedOpts = (() => {
181174
const _$1 = {};
175+
const computedKey = dynamicPrefix + "Id";
182176
for (const key in src) {
183-
if (!keysToExclude.includes(key)) _$1[key] = src[key];
177+
if (key !== computedKey) _$1[key] = src[key];
184178
}
185179
for (const key in a) {
186-
if (!keysToExclude.includes(key)) _$1[key] = a[key];
187-
}
188-
for (const key in b) {
189-
_$1[key] = b[key]; // No exclusions here since all keys in keysToExclude are skipped before this point
180+
_$1[key] = a[key];
190181
}
191182
return _$1;
192-
};
183+
})();
193184
```
194185

195186
---
196187

197188
## Advantages
198189

190+
- **Supports Dynamic and Complex Keys**: Handles variables and expressions as keys.
199191
- **Improved Readability**: Keeps code clean and declarative.
200-
- **Fine-Grained Control**: Allows exclusions at specific points in the spread expression.
201192
- **Performance Gains**: Avoids unnecessary property deletions by not copying excluded keys.
202193
- **Reduced Boilerplate**: Simplifies exclusion patterns in complex merges.
203194

204195
---
205196

206197
## Conclusion
207198

208-
The proposed key exclusion syntax improves the flexibility and clarity of object spread operations, addressing common pain points in JavaScript development. Its ability to operate contextually within spread expressions and its potential for performance optimization make it a valuable addition to the language.
199+
The proposed key exclusion syntax enhances the flexibility and clarity of object spread operations. Its ability to operate contextually and handle complex, dynamic keys makes it a powerful tool for JavaScript developers. By eliminating unnecessary object copies or deletions, it also provides performance benefits in large-scale applications.
209200

210201
Contributions and feedback are welcome!

0 commit comments

Comments
 (0)