0
# Map Object
1
2
Map Object provides a utility function for mapping object keys and values into new objects, supporting both shallow and deep transformation of nested structures. It offers a flexible mapper function that allows developers to rename keys, transform values, and selectively exclude properties using a special skip symbol, with built-in support for recursive processing of nested objects and arrays while maintaining proper circular reference handling.
3
4
## Package Information
5
6
- **Package Name**: map-obj
7
- **Package Type**: npm
8
- **Language**: JavaScript/TypeScript
9
- **Installation**: `npm install map-obj`
10
11
## Core Imports
12
13
```javascript
14
import mapObject, { mapObjectSkip } from "map-obj";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const mapObject = require("map-obj");
21
const { mapObjectSkip } = require("map-obj");
22
```
23
24
## Basic Usage
25
26
```javascript
27
import mapObject, { mapObjectSkip } from "map-obj";
28
29
// Transform keys and values
30
const result = mapObject({ foo: "bar" }, (key, value) => [value, key]);
31
// Result: { bar: "foo" }
32
33
// Transform keys (e.g., normalize case)
34
const normalized = mapObject(
35
{ FOO: true, bAr: { bAz: true } },
36
(key, value) => [key.toLowerCase(), value]
37
);
38
// Result: { foo: true, bar: { bAz: true } }
39
40
// Deep transformation
41
const deepNormalized = mapObject(
42
{ FOO: true, bAr: { bAz: true } },
43
(key, value) => [key.toLowerCase(), value],
44
{ deep: true }
45
);
46
// Result: { foo: true, bar: { baz: true } }
47
48
// Exclude properties using skip symbol
49
const filtered = mapObject(
50
{ one: 1, two: 2 },
51
(key, value) => (value === 1 ? [key, value] : mapObjectSkip)
52
);
53
// Result: { one: 1 }
54
```
55
56
## Capabilities
57
58
### Map Object Function
59
60
Maps object keys and values into a new object using a provided mapper function.
61
62
```typescript { .api }
63
/**
64
* Map object keys and values into a new object
65
* @param source - The source object to copy properties from
66
* @param mapper - A mapping function that transforms keys and values
67
* @param options - Optional configuration for mapping behavior
68
* @returns New object with mapped keys and values
69
*/
70
function mapObject<
71
SourceObjectType extends Record<string, unknown>,
72
TargetObjectType extends Record<string, any>,
73
MappedObjectKeyType extends string,
74
MappedObjectValueType,
75
>(
76
source: SourceObjectType,
77
mapper: Mapper<SourceObjectType, MappedObjectKeyType, MappedObjectValueType>,
78
options: DeepOptions & TargetOptions<TargetObjectType>
79
): TargetObjectType & Record<string, unknown>;
80
81
function mapObject<
82
SourceObjectType extends Record<string, unknown>,
83
MappedObjectKeyType extends string,
84
MappedObjectValueType,
85
>(
86
source: SourceObjectType,
87
mapper: Mapper<SourceObjectType, MappedObjectKeyType, MappedObjectValueType>,
88
options: DeepOptions
89
): Record<string, unknown>;
90
91
function mapObject<
92
SourceObjectType extends Record<string, any>,
93
TargetObjectType extends Record<string, any>,
94
MappedObjectKeyType extends string,
95
MappedObjectValueType,
96
>(
97
source: SourceObjectType,
98
mapper: Mapper<SourceObjectType, MappedObjectKeyType, MappedObjectValueType>,
99
options: TargetOptions<TargetObjectType>
100
): TargetObjectType & {[K in MappedObjectKeyType]: MappedObjectValueType};
101
102
function mapObject<
103
SourceObjectType extends Record<string, any>,
104
MappedObjectKeyType extends string,
105
MappedObjectValueType,
106
>(
107
source: SourceObjectType,
108
mapper: Mapper<SourceObjectType, MappedObjectKeyType, MappedObjectValueType>,
109
options?: Options
110
): {[K in MappedObjectKeyType]: MappedObjectValueType};
111
```
112
113
**Usage Examples:**
114
115
```javascript
116
// Key transformation
117
const camelCased = mapObject(
118
{ "first-name": "John", "last-name": "Doe" },
119
(key, value) => [key.replace(/-(\w)/g, (_, char) => char.toUpperCase()), value]
120
);
121
// Result: { firstName: "John", lastName: "Doe" }
122
123
// Value transformation
124
const doubled = mapObject(
125
{ a: 1, b: 2, c: 3 },
126
(key, value) => [key, value * 2]
127
);
128
// Result: { a: 2, b: 4, c: 6 }
129
130
// Using target option
131
const target = { existing: "value" };
132
const merged = mapObject(
133
{ new: "data" },
134
(key, value) => [key, value],
135
{ target }
136
);
137
// Result: target object is modified and returned
138
```
139
140
### Map Object Skip Symbol
141
142
Special symbol returned from a mapper function to exclude a key from the result object.
143
144
```typescript { .api }
145
/**
146
* Return this value from a mapper function to remove a key from an object
147
*/
148
const mapObjectSkip: unique symbol;
149
```
150
151
**Usage Examples:**
152
153
```javascript
154
import mapObject, { mapObjectSkip } from "map-obj";
155
156
// Conditional inclusion
157
const adults = mapObject(
158
{ alice: 25, bob: 16, charlie: 30 },
159
(key, value) => (value >= 18 ? [key, value] : mapObjectSkip)
160
);
161
// Result: { alice: 25, charlie: 30 }
162
163
// Property filtering based on key patterns
164
const publicProps = mapObject(
165
{ name: "John", _private: "secret", age: 30, _id: 123 },
166
(key, value) => (key.startsWith("_") ? mapObjectSkip : [key, value])
167
);
168
// Result: { name: "John", age: 30 }
169
```
170
171
## Types
172
173
### Mapper Function Type
174
175
```typescript { .api }
176
type Mapper<
177
SourceObjectType extends Record<string, any>,
178
MappedObjectKeyType extends string,
179
MappedObjectValueType,
180
> = (
181
sourceKey: keyof SourceObjectType,
182
sourceValue: SourceObjectType[keyof SourceObjectType],
183
source: SourceObjectType
184
) => [
185
targetKey: MappedObjectKeyType,
186
targetValue: MappedObjectValueType,
187
mapperOptions?: MapperOptions,
188
] | typeof mapObjectSkip;
189
```
190
191
### Options Interface
192
193
```typescript { .api }
194
interface Options {
195
/**
196
* Recurse nested objects and objects in arrays
197
* @default false
198
*/
199
readonly deep?: boolean;
200
201
/**
202
* The target object to map properties on to
203
* @default {}
204
*/
205
readonly target?: Record<string, any>;
206
}
207
```
208
209
### Deep Options Interface
210
211
```typescript { .api }
212
interface DeepOptions extends Options {
213
readonly deep: true;
214
}
215
```
216
217
### Target Options Interface
218
219
```typescript { .api }
220
interface TargetOptions<TargetObjectType extends Record<string, any>> extends Options {
221
readonly target: TargetObjectType;
222
}
223
```
224
225
### Mapper Options Interface
226
227
```typescript { .api }
228
interface MapperOptions {
229
/**
230
* Whether targetValue should be recursed
231
* Requires deep: true
232
* @default true
233
*/
234
readonly shouldRecurse?: boolean;
235
}
236
```
237
238
## Advanced Usage
239
240
### Deep Object Mapping
241
242
```javascript
243
const nested = {
244
user: {
245
profile: {
246
firstName: "John",
247
lastName: "Doe"
248
},
249
preferences: ["email", "sms"]
250
}
251
};
252
253
const normalized = mapObject(
254
nested,
255
(key, value) => [key.toLowerCase(), value],
256
{ deep: true }
257
);
258
// All nested keys are transformed recursively
259
```
260
261
### Selective Recursion Control
262
263
```javascript
264
const data = {
265
metadata: { version: "1.0", author: "John" },
266
content: { title: "Example", body: "Content here" }
267
};
268
269
const result = mapObject(
270
data,
271
(key, value) => {
272
if (key === "metadata") {
273
// Don't recurse into metadata
274
return [key, value, { shouldRecurse: false }];
275
}
276
return [key.toUpperCase(), value];
277
},
278
{ deep: true }
279
);
280
// metadata object is not recursively transformed
281
```
282
283
### Circular Reference Handling
284
285
```javascript
286
const obj = { name: "test" };
287
obj.self = obj; // Create circular reference
288
289
const mapped = mapObject(
290
obj,
291
(key, value) => [key.toUpperCase(), value],
292
{ deep: true }
293
);
294
// Circular references are handled automatically using WeakMap tracking
295
```
296
297
## Error Handling
298
299
The `mapObject` function validates its input and throws `TypeError` in the following cases:
300
301
- When the first argument is not an object: `TypeError: Expected an object, got \`value\` (type)`
302
- When the first argument is an array: `TypeError: Expected an object, got an array`
303
304
```javascript
305
try {
306
mapObject(null, (k, v) => [k, v]);
307
} catch (error) {
308
console.log(error.message); // "Expected an object, got `null` (object)"
309
}
310
311
try {
312
mapObject([1, 2, 3], (k, v) => [k, v]);
313
} catch (error) {
314
console.log(error.message); // "Expected an object, got an array"
315
}
316
```