@helpers4/object 2.0.4 → 3.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/meta/api.json CHANGED
@@ -1,98 +1,26 @@
1
1
  {
2
2
  "category": "object",
3
- "version": "2.0.4",
3
+ "version": "3.0.0-alpha.1",
4
4
  "functions": [
5
5
  {
6
- "name": "compact",
7
- "kind": "function",
8
- "description": "Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `\"\"`, `NaN`) from an object.",
9
- "since": "2.0.0",
10
- "signatures": [
11
- {
12
- "signature": "compact<T extends Record<string, unknown>>(obj: T): Partial<T>",
13
- "description": "Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `\"\"`, `NaN`) from an object.",
14
- "params": [
15
- {
16
- "name": "obj",
17
- "type": "T",
18
- "description": "The source object"
19
- }
20
- ],
21
- "returns": {
22
- "type": "Partial<T>",
23
- "description": "A new object containing only entries with truthy values"
24
- },
25
- "typeParameters": [
26
- {
27
- "name": "T",
28
- "constraint": "Record<string, unknown>"
29
- }
30
- ]
31
- },
32
- {
33
- "signature": "compact(obj: undefined): undefined",
34
- "description": "Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `\"\"`, `NaN`) from an object.",
35
- "params": [
36
- {
37
- "name": "obj",
38
- "type": "undefined",
39
- "description": "The source object"
40
- }
41
- ],
42
- "returns": {
43
- "type": "undefined",
44
- "description": "A new object containing only entries with truthy values"
45
- }
46
- },
47
- {
48
- "signature": "compact(obj: null): null",
49
- "description": "Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `\"\"`, `NaN`) from an object.",
50
- "params": [
51
- {
52
- "name": "obj",
53
- "type": "null",
54
- "description": "The source object"
55
- }
56
- ],
57
- "returns": {
58
- "type": "null",
59
- "description": "A new object containing only entries with truthy values"
60
- }
61
- }
62
- ],
63
- "examples": [
64
- {
65
- "title": "Remove falsy values from object",
66
- "description": "Removes all entries with falsy values (false, null, undefined, 0, \"\", NaN).",
67
- "code": "compact({ a: 1, b: null, c: '', d: 0, e: 'hello' })\n// => { a: 1, e: 'hello' }"
68
- },
69
- {
70
- "title": "Clean up API response",
71
- "description": "Useful to strip empty or missing fields before sending data.",
72
- "code": "compact({ name: 'Alice', email: '', age: 0, role: 'admin' })\n// => { name: 'Alice', role: 'admin' }"
73
- }
74
- ],
75
- "sourceFile": "compact.ts"
76
- },
77
- {
78
- "name": "deepClone",
6
+ "name": "cloneDeep",
79
7
  "kind": "function",
80
- "description": "Creates a deep copy of an object or array",
8
+ "description": "Creates a deep copy of an object or array.\n\nRecursively clones own enumerable string keys. `Date` instances are\nreconstructed with the same epoch value. Prototype-polluting keys\n(`__proto__`, `constructor`, `prototype`) are silently skipped.\nDoes **not** handle circular references.\n\n**Limitation:** symbol-keyed own properties are **not** copied — only string\nkeys are processed. Use `structuredClone` if symbol propagation is required.",
81
9
  "since": "1.9.0",
82
10
  "signatures": [
83
11
  {
84
- "signature": "deepClone<T>(obj: T): T",
85
- "description": "Creates a deep copy of an object or array",
12
+ "signature": "cloneDeep<T>(obj: T): T",
13
+ "description": "Creates a deep copy of an object or array.\n\nRecursively clones own enumerable string keys. `Date` instances are\nreconstructed with the same epoch value. Prototype-polluting keys\n(`__proto__`, `constructor`, `prototype`) are silently skipped.\nDoes **not** handle circular references.\n\n**Limitation:** symbol-keyed own properties are **not** copied — only string\nkeys are processed. Use `structuredClone` if symbol propagation is required.",
86
14
  "params": [
87
15
  {
88
16
  "name": "obj",
89
17
  "type": "T",
90
- "description": "The object to clone"
18
+ "description": "The value to clone"
91
19
  }
92
20
  ],
93
21
  "returns": {
94
22
  "type": "T",
95
- "description": "Deep cloned object"
23
+ "description": "A deep copy of `obj`"
96
24
  },
97
25
  "typeParameters": [
98
26
  {
@@ -105,92 +33,82 @@
105
33
  {
106
34
  "title": "Clone a nested object",
107
35
  "description": "Creates a deep copy — modifying the clone does not affect the original.",
108
- "code": "const original = { a: { b: 1 } };\nconst cloned = deepClone(original);\ncloned.a.b = 2;\n// original.a.b is still 1"
36
+ "code": "const original = { a: { b: 1 } };\nconst cloned = cloneDeep(original);\ncloned.a.b = 2;\n// original.a.b is still 1"
109
37
  }
110
38
  ],
111
- "sourceFile": "deepClone.ts"
39
+ "sourceFile": "cloneDeep.ts"
112
40
  },
113
41
  {
114
- "name": "deepMerge",
42
+ "name": "compact",
115
43
  "kind": "function",
116
- "description": "Merges two or more objects deeply.\n\nRecursively merges own enumerable properties — both string and symbol keys.\nPlain objects are merged recursively; all other values (arrays, class instances,\nprimitives, etc.) are replaced by the source value.\n`undefined` source values do not overwrite existing target values.",
117
- "since": "1.9.0",
44
+ "description": "Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `\"\"`, `NaN`) from an object.\nOwn keys that are prototype-polluting strings (`__proto__`, `constructor`, `prototype`) are\nsilently skipped.",
45
+ "since": "2.0.0",
118
46
  "signatures": [
119
47
  {
120
- "signature": "deepMerge<T extends Record<PropertyKey, unknown>>(target: T, sources: Record<PropertyKey, unknown>[]): T",
121
- "description": "Merges two or more objects deeply.\n\nRecursively merges own enumerable properties — both string and symbol keys.\nPlain objects are merged recursively; all other values (arrays, class instances,\nprimitives, etc.) are replaced by the source value.\n`undefined` source values do not overwrite existing target values.",
48
+ "signature": "compact<T extends Record<string, unknown>>(obj: T): Partial<T>",
49
+ "description": "Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `\"\"`, `NaN`) from an object.\nOwn keys that are prototype-polluting strings (`__proto__`, `constructor`, `prototype`) are\nsilently skipped.",
122
50
  "params": [
123
51
  {
124
- "name": "target",
52
+ "name": "obj",
125
53
  "type": "T",
126
- "description": "The target object (mutated in place)"
127
- },
128
- {
129
- "name": "sources",
130
- "type": "Record<PropertyKey, unknown>[]",
131
- "description": "One or more source objects to merge into the target"
54
+ "description": "The source object"
132
55
  }
133
56
  ],
134
57
  "returns": {
135
- "type": "T",
136
- "description": "The mutated target"
58
+ "type": "Partial<T>",
59
+ "description": "A new object containing only entries with truthy values"
137
60
  },
138
61
  "typeParameters": [
139
62
  {
140
63
  "name": "T",
141
- "constraint": "Record<PropertyKey, unknown>"
64
+ "constraint": "Record<string, unknown>"
142
65
  }
143
66
  ]
144
67
  },
145
68
  {
146
- "signature": "deepMerge(target: undefined, sources: Record<PropertyKey, unknown>[]): undefined",
147
- "description": "Merges two or more objects deeply.\n\nRecursively merges own enumerable properties — both string and symbol keys.\nPlain objects are merged recursively; all other values (arrays, class instances,\nprimitives, etc.) are replaced by the source value.\n`undefined` source values do not overwrite existing target values.",
69
+ "signature": "compact(obj: undefined): undefined",
70
+ "description": "Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `\"\"`, `NaN`) from an object.\nOwn keys that are prototype-polluting strings (`__proto__`, `constructor`, `prototype`) are\nsilently skipped.",
148
71
  "params": [
149
72
  {
150
- "name": "target",
73
+ "name": "obj",
151
74
  "type": "undefined",
152
- "description": "The target object (mutated in place)"
153
- },
154
- {
155
- "name": "sources",
156
- "type": "Record<PropertyKey, unknown>[]",
157
- "description": "One or more source objects to merge into the target"
75
+ "description": "The source object"
158
76
  }
159
77
  ],
160
78
  "returns": {
161
79
  "type": "undefined",
162
- "description": "The mutated target"
80
+ "description": "A new object containing only entries with truthy values"
163
81
  }
164
82
  },
165
83
  {
166
- "signature": "deepMerge(target: null, sources: Record<PropertyKey, unknown>[]): null",
167
- "description": "Merges two or more objects deeply.\n\nRecursively merges own enumerable properties — both string and symbol keys.\nPlain objects are merged recursively; all other values (arrays, class instances,\nprimitives, etc.) are replaced by the source value.\n`undefined` source values do not overwrite existing target values.",
84
+ "signature": "compact(obj: null): null",
85
+ "description": "Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `\"\"`, `NaN`) from an object.\nOwn keys that are prototype-polluting strings (`__proto__`, `constructor`, `prototype`) are\nsilently skipped.",
168
86
  "params": [
169
87
  {
170
- "name": "target",
88
+ "name": "obj",
171
89
  "type": "null",
172
- "description": "The target object (mutated in place)"
173
- },
174
- {
175
- "name": "sources",
176
- "type": "Record<PropertyKey, unknown>[]",
177
- "description": "One or more source objects to merge into the target"
90
+ "description": "The source object"
178
91
  }
179
92
  ],
180
93
  "returns": {
181
94
  "type": "null",
182
- "description": "The mutated target"
95
+ "description": "A new object containing only entries with truthy values"
183
96
  }
184
97
  }
185
98
  ],
186
99
  "examples": [
187
100
  {
188
- "title": "Merge two objects deeply",
189
- "description": "Recursively merges source properties into the target object.",
190
- "code": "deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 }, e: 4 })\n// => { a: 1, b: { c: 2, d: 3 }, e: 4 }"
101
+ "title": "Remove falsy values from object",
102
+ "description": "Removes all entries with falsy values (false, null, undefined, 0, \"\", NaN).",
103
+ "code": "compact({ a: 1, b: null, c: '', d: 0, e: 'hello' })\n// => { a: 1, e: 'hello' }"
104
+ },
105
+ {
106
+ "title": "Clean up API response",
107
+ "description": "Useful to strip empty or missing fields before sending data.",
108
+ "code": "compact({ name: 'Alice', email: '', age: 0, role: 'admin' })\n// => { name: 'Alice', role: 'admin' }"
191
109
  }
192
110
  ],
193
- "sourceFile": "deepMerge.ts"
111
+ "sourceFile": "compact.ts"
194
112
  },
195
113
  {
196
114
  "name": "diff",
@@ -331,64 +249,82 @@
331
249
  {
332
250
  "name": "get",
333
251
  "kind": "function",
334
- "description": "Gets a value from an object using a dot/bracket-notated path or explicit key array.\n\n**Two path forms are supported:**\n\n1. **String path** — dot notation (`'a.b.c'`) and bracket notation (`'layers[1].name'`)\n are both accepted and mixed freely. Segments are traversed as string keys; `[n]`\n indices become numeric keys.\n\n2. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables symbol-keyed traversal and compile-time type inference:\n `get(obj, ['a', 'b'] as const)` infers the return type from the path.",
252
+ "description": "Gets a value from an object using a dot/bracket-notated path or explicit key array.\n\n**Two path forms are supported:**\n\n1. **String path** — dot notation (`'a.b.c'`) and bracket notation (`'layers[1].name'`)\n are both accepted and mixed freely.\n - Dot segments are always string keys: `'a.1'` → key `'1'` (string).\n - Bracket segments are always number keys: `'a[1]'` → key `1` (number).\n - String literal paths give **full compile-time type inference** on the return type.\n - Dynamic (non-literal) strings return `unknown`.\n\n2. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables symbol-keyed traversal and compile-time type inference:\n `get(obj, ['a', 'b'] as const)` infers the return type from the path.\n\nBoth forms support **all objects** (plain objects, arrays, class instances).\nSymbol keys are only reachable via the key-array form.",
335
253
  "since": "1.9.0",
336
254
  "signatures": [
337
255
  {
338
- "signature": "get<T = unknown>(obj: unknown, path: string, defaultValue?: T): T | undefined",
339
- "description": "Gets a value from an object using a dot/bracket-notated path or explicit key array.\n\n**Two path forms are supported:**\n\n1. **String path** — dot notation (`'a.b.c'`) and bracket notation (`'layers[1].name'`)\n are both accepted and mixed freely. Segments are traversed as string keys; `[n]`\n indices become numeric keys.\n\n2. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables symbol-keyed traversal and compile-time type inference:\n `get(obj, ['a', 'b'] as const)` infers the return type from the path.",
256
+ "signature": "get<D>(obj: null | undefined, path: string | readonly PropertyKey[], defaultValue: D): D",
257
+ "description": "Gets a value from an object using a dot/bracket-notated path or explicit key array.\n\n**Two path forms are supported:**\n\n1. **String path** — dot notation (`'a.b.c'`) and bracket notation (`'layers[1].name'`)\n are both accepted and mixed freely.\n - Dot segments are always string keys: `'a.1'` → key `'1'` (string).\n - Bracket segments are always number keys: `'a[1]'` → key `1` (number).\n - String literal paths give **full compile-time type inference** on the return type.\n - Dynamic (non-literal) strings return `unknown`.\n\n2. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables symbol-keyed traversal and compile-time type inference:\n `get(obj, ['a', 'b'] as const)` infers the return type from the path.\n\nBoth forms support **all objects** (plain objects, arrays, class instances).\nSymbol keys are only reachable via the key-array form.",
340
258
  "params": [
341
259
  {
342
260
  "name": "obj",
343
- "type": "unknown",
261
+ "type": "null | undefined",
344
262
  "description": "The object to read from"
345
263
  },
346
264
  {
347
265
  "name": "path",
348
- "type": "string",
349
- "description": "Dot/bracket-notation string or explicit `PropertyKey[]`"
266
+ "type": "string | readonly PropertyKey[]",
267
+ "description": "Dot/bracket-notation string literal or explicit `PropertyKey[]`"
350
268
  },
351
269
  {
352
270
  "name": "defaultValue",
353
- "type": "T",
354
- "description": "Returned when the path is absent or resolves to `undefined`",
355
- "optional": true
271
+ "type": "D",
272
+ "description": "Returned when the path is absent or resolves to `undefined`"
356
273
  }
357
274
  ],
358
275
  "returns": {
359
- "type": "T | undefined",
276
+ "type": "D",
360
277
  "description": "The value at the path, or `defaultValue`"
361
278
  },
362
279
  "typeParameters": [
363
280
  {
364
- "name": "T",
365
- "default": "unknown"
281
+ "name": "D"
366
282
  }
367
283
  ]
368
284
  },
369
285
  {
370
- "signature": "get<T extends object, Path extends readonly PropertyKey[]>(obj: T, path: Path, defaultValue?: DeepGet<T, Path>): DeepGet<T, Path> | undefined",
371
- "description": "Gets a value from an object using a dot/bracket-notated path or explicit key array.\n\n**Two path forms are supported:**\n\n1. **String path** — dot notation (`'a.b.c'`) and bracket notation (`'layers[1].name'`)\n are both accepted and mixed freely. Segments are traversed as string keys; `[n]`\n indices become numeric keys.\n\n2. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables symbol-keyed traversal and compile-time type inference:\n `get(obj, ['a', 'b'] as const)` infers the return type from the path.",
286
+ "signature": "get(obj: null | undefined, path: string | readonly PropertyKey[]): undefined",
287
+ "description": "Gets a value from an object using a dot/bracket-notated path or explicit key array.\n\n**Two path forms are supported:**\n\n1. **String path** — dot notation (`'a.b.c'`) and bracket notation (`'layers[1].name'`)\n are both accepted and mixed freely.\n - Dot segments are always string keys: `'a.1'` → key `'1'` (string).\n - Bracket segments are always number keys: `'a[1]'` → key `1` (number).\n - String literal paths give **full compile-time type inference** on the return type.\n - Dynamic (non-literal) strings return `unknown`.\n\n2. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables symbol-keyed traversal and compile-time type inference:\n `get(obj, ['a', 'b'] as const)` infers the return type from the path.\n\nBoth forms support **all objects** (plain objects, arrays, class instances).\nSymbol keys are only reachable via the key-array form.",
372
288
  "params": [
373
289
  {
374
290
  "name": "obj",
375
- "type": "T",
291
+ "type": "null | undefined",
292
+ "description": "The object to read from"
293
+ },
294
+ {
295
+ "name": "path",
296
+ "type": "string | readonly PropertyKey[]",
297
+ "description": "Dot/bracket-notation string literal or explicit `PropertyKey[]`"
298
+ }
299
+ ],
300
+ "returns": {
301
+ "type": "undefined",
302
+ "description": "The value at the path, or `defaultValue`"
303
+ }
304
+ },
305
+ {
306
+ "signature": "get<T extends object, P extends string | readonly PropertyKey[]>(obj: T | null | undefined, path: P, defaultValue?: DeepGet<T, ParsePath<P>>): DeepGet<T, ParsePath<P>> | undefined",
307
+ "description": "Gets a value from an object using a dot/bracket-notated path or explicit key array.\n\n**Two path forms are supported:**\n\n1. **String path** — dot notation (`'a.b.c'`) and bracket notation (`'layers[1].name'`)\n are both accepted and mixed freely.\n - Dot segments are always string keys: `'a.1'` → key `'1'` (string).\n - Bracket segments are always number keys: `'a[1]'` → key `1` (number).\n - String literal paths give **full compile-time type inference** on the return type.\n - Dynamic (non-literal) strings return `unknown`.\n\n2. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables symbol-keyed traversal and compile-time type inference:\n `get(obj, ['a', 'b'] as const)` infers the return type from the path.\n\nBoth forms support **all objects** (plain objects, arrays, class instances).\nSymbol keys are only reachable via the key-array form.",
308
+ "params": [
309
+ {
310
+ "name": "obj",
311
+ "type": "T | null | undefined",
376
312
  "description": "The object to read from"
377
313
  },
378
314
  {
379
315
  "name": "path",
380
- "type": "Path",
381
- "description": "Dot/bracket-notation string or explicit `PropertyKey[]`"
316
+ "type": "P",
317
+ "description": "Dot/bracket-notation string literal or explicit `PropertyKey[]`"
382
318
  },
383
319
  {
384
320
  "name": "defaultValue",
385
- "type": "DeepGet<T, Path>",
321
+ "type": "DeepGet<T, ParsePath<P>>",
386
322
  "description": "Returned when the path is absent or resolves to `undefined`",
387
323
  "optional": true
388
324
  }
389
325
  ],
390
326
  "returns": {
391
- "type": "DeepGet<T, Path> | undefined",
327
+ "type": "DeepGet<T, ParsePath<P>> | undefined",
392
328
  "description": "The value at the path, or `defaultValue`"
393
329
  },
394
330
  "typeParameters": [
@@ -397,8 +333,8 @@
397
333
  "constraint": "object"
398
334
  },
399
335
  {
400
- "name": "Path",
401
- "constraint": "readonly PropertyKey[]"
336
+ "name": "P",
337
+ "constraint": "string | readonly PropertyKey[]"
402
338
  }
403
339
  ]
404
340
  }
@@ -425,16 +361,16 @@
425
361
  {
426
362
  "name": "groupBy",
427
363
  "kind": "function",
428
- "description": "Groups an array of items by a key derived from each item.\n\nA thin, typed wrapper around `Object.groupBy` (ES2024) that works on\nolder targets and provides stricter return-type inference.",
364
+ "description": "Groups an array of items by a key derived from each item.\n\nA thin, typed wrapper around `Object.groupBy` (ES2024) that works on\nolder targets and provides stricter return-type inference.\n`null` and `undefined` are treated as empty arrays and return `{}`.\nItems whose computed key is a prototype-polluting string (`__proto__`,\n`constructor`, `prototype`) are silently skipped.",
429
365
  "since": "2.0.0",
430
366
  "signatures": [
431
367
  {
432
- "signature": "groupBy<T, K extends PropertyKey>(items: readonly T[], keyFn: function): Partial<Record<K, T[]>>",
433
- "description": "Groups an array of items by a key derived from each item.\n\nA thin, typed wrapper around `Object.groupBy` (ES2024) that works on\nolder targets and provides stricter return-type inference.",
368
+ "signature": "groupBy<T, K extends PropertyKey>(items: readonly T[] | null | undefined, keyFn: function): Partial<Record<K, T[]>>",
369
+ "description": "Groups an array of items by a key derived from each item.\n\nA thin, typed wrapper around `Object.groupBy` (ES2024) that works on\nolder targets and provides stricter return-type inference.\n`null` and `undefined` are treated as empty arrays and return `{}`.\nItems whose computed key is a prototype-polluting string (`__proto__`,\n`constructor`, `prototype`) are silently skipped.",
434
370
  "params": [
435
371
  {
436
372
  "name": "items",
437
- "type": "readonly T[]",
373
+ "type": "readonly T[] | null | undefined",
438
374
  "description": "The array to group"
439
375
  },
440
376
  {
@@ -475,16 +411,16 @@
475
411
  {
476
412
  "name": "invert",
477
413
  "kind": "function",
478
- "description": "Returns a new object with keys and values swapped.\nIf multiple keys share the same value, the last one wins.",
414
+ "description": "Returns a new object with keys and values swapped.\nIf multiple keys share the same value, the last one wins.\n`null` and `undefined` are treated as empty objects and return `{}`.\nEntries whose source key **or** value is a prototype-polluting string\n(`__proto__`, `constructor`, `prototype`) are silently skipped.",
479
415
  "since": "2.0.0",
480
416
  "signatures": [
481
417
  {
482
- "signature": "invert<K extends string, V extends PropertyKey>(obj: Record<K, V>): Record<V, K>",
483
- "description": "Returns a new object with keys and values swapped.\nIf multiple keys share the same value, the last one wins.",
418
+ "signature": "invert<K extends string, V extends PropertyKey>(obj: Record<K, V> | null | undefined): Record<V, K>",
419
+ "description": "Returns a new object with keys and values swapped.\nIf multiple keys share the same value, the last one wins.\n`null` and `undefined` are treated as empty objects and return `{}`.\nEntries whose source key **or** value is a prototype-polluting string\n(`__proto__`, `constructor`, `prototype`) are silently skipped.",
484
420
  "params": [
485
421
  {
486
422
  "name": "obj",
487
- "type": "Record<K, V>",
423
+ "type": "Record<K, V> | null | undefined",
488
424
  "description": "The object whose keys and values are to be swapped"
489
425
  }
490
426
  ],
@@ -521,22 +457,22 @@
521
457
  {
522
458
  "name": "isEmpty",
523
459
  "kind": "function",
524
- "description": "Checks if a plain object has no own enumerable string-keyed properties.\n\nSymbol-keyed properties are not counted. Use `Object.getOwnPropertySymbols`\nseparately if symbol keys matter for your use case.",
460
+ "description": "Checks if a plain object has no own enumerable string-keyed properties.\n`null` and `undefined` are treated as empty objects and return `true`.\n\nSymbol-keyed properties are not counted. Use `Object.getOwnPropertySymbols`\nseparately if symbol keys matter for your use case.",
525
461
  "since": "2.0.3",
526
462
  "signatures": [
527
463
  {
528
- "signature": "isEmpty(value: Record<PropertyKey, unknown>): boolean",
529
- "description": "Checks if a plain object has no own enumerable string-keyed properties.\n\nSymbol-keyed properties are not counted. Use `Object.getOwnPropertySymbols`\nseparately if symbol keys matter for your use case.",
464
+ "signature": "isEmpty(value: Record<PropertyKey, unknown> | null | undefined): boolean",
465
+ "description": "Checks if a plain object has no own enumerable string-keyed properties.\n`null` and `undefined` are treated as empty objects and return `true`.\n\nSymbol-keyed properties are not counted. Use `Object.getOwnPropertySymbols`\nseparately if symbol keys matter for your use case.",
530
466
  "params": [
531
467
  {
532
468
  "name": "value",
533
- "type": "Record<PropertyKey, unknown>",
469
+ "type": "Record<PropertyKey, unknown> | null | undefined",
534
470
  "description": "The object to check"
535
471
  }
536
472
  ],
537
473
  "returns": {
538
474
  "type": "boolean",
539
- "description": "`true` if the object has no own enumerable string-keyed properties"
475
+ "description": "`true` if the object has no own enumerable string-keyed properties, or if `value` is `null`/`undefined`"
540
476
  }
541
477
  }
542
478
  ],
@@ -557,22 +493,22 @@
557
493
  {
558
494
  "name": "isNonEmpty",
559
495
  "kind": "function",
560
- "description": "Checks if a plain object has at least one own enumerable string-keyed property.\n\nSymbol-keyed properties are not counted. Use `Object.getOwnPropertySymbols`\nseparately if symbol keys matter for your use case.",
496
+ "description": "Checks if a plain object has at least one own enumerable string-keyed property.\n`null` and `undefined` are treated as empty objects and return `false`.\n\nSymbol-keyed properties are not counted. Use `Object.getOwnPropertySymbols`\nseparately if symbol keys matter for your use case.",
561
497
  "since": "2.0.3",
562
498
  "signatures": [
563
499
  {
564
- "signature": "isNonEmpty(value: Record<PropertyKey, unknown>): boolean",
565
- "description": "Checks if a plain object has at least one own enumerable string-keyed property.\n\nSymbol-keyed properties are not counted. Use `Object.getOwnPropertySymbols`\nseparately if symbol keys matter for your use case.",
500
+ "signature": "isNonEmpty(value: Record<PropertyKey, unknown> | null | undefined): value is Record<PropertyKey, unknown>",
501
+ "description": "Checks if a plain object has at least one own enumerable string-keyed property.\n`null` and `undefined` are treated as empty objects and return `false`.\n\nSymbol-keyed properties are not counted. Use `Object.getOwnPropertySymbols`\nseparately if symbol keys matter for your use case.",
566
502
  "params": [
567
503
  {
568
504
  "name": "value",
569
- "type": "Record<PropertyKey, unknown>",
505
+ "type": "Record<PropertyKey, unknown> | null | undefined",
570
506
  "description": "The object to check"
571
507
  }
572
508
  ],
573
509
  "returns": {
574
- "type": "boolean",
575
- "description": "`true` if the object has at least one own enumerable string-keyed property"
510
+ "type": "value is Record<PropertyKey, unknown>",
511
+ "description": "`true` if the object has at least one own enumerable string-keyed property; `false` for empty, `null`, or `undefined`.\nActs as a type guard: the `if` branch narrows `Record<PropertyKey, unknown> | null | undefined` to `Record<PropertyKey, unknown>`."
576
512
  }
577
513
  }
578
514
  ],
@@ -593,16 +529,16 @@
593
529
  {
594
530
  "name": "map",
595
531
  "kind": "function",
596
- "description": "Transforms the values and/or keys of a plain object in a single pass.\n\nBoth callbacks are optional and default to identity (no transformation).\nWhen `mapValue` is omitted the original values are preserved;\nwhen `mapKey` is omitted the original keys are preserved.\n\nNote: if two different keys map to the same output key the last one wins\n(insertion order).",
532
+ "description": "Transforms the values and/or keys of a plain object in a single pass.\n\nBoth callbacks are optional and default to identity (no transformation).\nWhen `mapValue` is omitted the original values are preserved;\nwhen `mapKey` is omitted the original keys are preserved.\n\nNote: if two different keys map to the same output key the last one wins\n(insertion order). Entries whose mapped key is a prototype-polluting string\n(`__proto__`, `constructor`, `prototype`) are silently skipped.",
597
533
  "since": "2.0.0",
598
534
  "signatures": [
599
535
  {
600
- "signature": "map<TObj extends Record<string, unknown>, TVal = indexedAccess, TKey extends PropertyKey = keyof TObj>(obj: TObj, mapValue?: function, mapKey?: function): Record<TKey, TVal>",
601
- "description": "Transforms the values and/or keys of a plain object in a single pass.\n\nBoth callbacks are optional and default to identity (no transformation).\nWhen `mapValue` is omitted the original values are preserved;\nwhen `mapKey` is omitted the original keys are preserved.\n\nNote: if two different keys map to the same output key the last one wins\n(insertion order).",
536
+ "signature": "map<TObj extends Record<string, unknown>, TVal = indexedAccess, TKey extends PropertyKey = keyof TObj>(obj: TObj | null | undefined, mapValue?: function, mapKey?: function): Record<TKey, TVal>",
537
+ "description": "Transforms the values and/or keys of a plain object in a single pass.\n\nBoth callbacks are optional and default to identity (no transformation).\nWhen `mapValue` is omitted the original values are preserved;\nwhen `mapKey` is omitted the original keys are preserved.\n\nNote: if two different keys map to the same output key the last one wins\n(insertion order). Entries whose mapped key is a prototype-polluting string\n(`__proto__`, `constructor`, `prototype`) are silently skipped.",
602
538
  "params": [
603
539
  {
604
540
  "name": "obj",
605
- "type": "TObj",
541
+ "type": "TObj | null | undefined",
606
542
  "description": "The source object"
607
543
  },
608
544
  {
@@ -658,6 +594,43 @@
658
594
  ],
659
595
  "sourceFile": "map.ts"
660
596
  },
597
+ {
598
+ "name": "mergeDeep",
599
+ "kind": "function",
600
+ "description": "Merges two or more objects deeply, returning a **new** object without mutating any input.\n\nSources are applied left to right. For each key:\n- If both sides are plain objects → merged recursively into a new object.\n- Otherwise → **later source wins** (the earlier value is overwritten).\n- `undefined` in a source **never overwrites** an existing value.\n- `null` in a source **does overwrite** and prevents a later source from\n deep-merging into that key: `mergeDeep({ a: { x: 1 } }, { a: null }, { a: { y: 2 } })`\n → `{ a: { y: 2 } }` — `x: 1` is permanently lost.\n- Arrays, class instances, and all non-plain-object values are **replaced**, not merged.\n\nOwn enumerable string and symbol keys of each source are processed at the top level;\ninherited and non-enumerable properties are skipped. Prototype-polluting keys\n(`__proto__`, `constructor`, `prototype`) are silently ignored.\n**Note:** symbol keys inside nested plain-object values are not preserved — they are\nlost when those values are deep-cloned. Only top-level symbol keys survive.\n\n**TypeScript return type — intersection semantics**\n\nThe return type is `A & B & C …` (intersection of all source types). This is accurate\nwhen keys are disjoint or share the same type:\n```ts\nmergeDeep({ a: 1 }, { b: 'x' }) // { a: number } & { b: string } ✓\nmergeDeep({ a: { b: 1 } }, { a: { c: 2 } }) // { a: { b: number } & { c: number } } ✓\n```\nWhen the same key carries **incompatible types** across sources, the intersection\nresolves to `never` for that key — TypeScript surfaces the conflict rather than\nsilently picking a type:\n```ts\nmergeDeep({ a: 1 }, { a: 'x' }) // { a: never } ← type conflict detected\n```\nAt runtime the later source always wins (`'x'`), but the `never` type signals that\nthe caller should align their source types. If intentional, cast the result.",
601
+ "since": "1.9.0",
602
+ "signatures": [
603
+ {
604
+ "signature": "mergeDeep<T extends [object, rest]>(sources: [rest]): MergeResult<T>",
605
+ "description": "Merges two or more objects deeply, returning a **new** object without mutating any input.\n\nSources are applied left to right. For each key:\n- If both sides are plain objects → merged recursively into a new object.\n- Otherwise → **later source wins** (the earlier value is overwritten).\n- `undefined` in a source **never overwrites** an existing value.\n- `null` in a source **does overwrite** and prevents a later source from\n deep-merging into that key: `mergeDeep({ a: { x: 1 } }, { a: null }, { a: { y: 2 } })`\n → `{ a: { y: 2 } }` — `x: 1` is permanently lost.\n- Arrays, class instances, and all non-plain-object values are **replaced**, not merged.\n\nOwn enumerable string and symbol keys of each source are processed at the top level;\ninherited and non-enumerable properties are skipped. Prototype-polluting keys\n(`__proto__`, `constructor`, `prototype`) are silently ignored.\n**Note:** symbol keys inside nested plain-object values are not preserved — they are\nlost when those values are deep-cloned. Only top-level symbol keys survive.\n\n**TypeScript return type — intersection semantics**\n\nThe return type is `A & B & C …` (intersection of all source types). This is accurate\nwhen keys are disjoint or share the same type:\n```ts\nmergeDeep({ a: 1 }, { b: 'x' }) // { a: number } & { b: string } ✓\nmergeDeep({ a: { b: 1 } }, { a: { c: 2 } }) // { a: { b: number } & { c: number } } ✓\n```\nWhen the same key carries **incompatible types** across sources, the intersection\nresolves to `never` for that key — TypeScript surfaces the conflict rather than\nsilently picking a type:\n```ts\nmergeDeep({ a: 1 }, { a: 'x' }) // { a: never } ← type conflict detected\n```\nAt runtime the later source always wins (`'x'`), but the `never` type signals that\nthe caller should align their source types. If intentional, cast the result.",
606
+ "params": [
607
+ {
608
+ "name": "sources",
609
+ "type": "[rest]",
610
+ "description": "Two or more objects to merge (none are mutated)"
611
+ }
612
+ ],
613
+ "returns": {
614
+ "type": "MergeResult<T>",
615
+ "description": "A new object that is the deep merge of all sources"
616
+ },
617
+ "typeParameters": [
618
+ {
619
+ "name": "T",
620
+ "constraint": "[object, rest]"
621
+ }
622
+ ]
623
+ }
624
+ ],
625
+ "examples": [
626
+ {
627
+ "title": "Merge two objects deeply",
628
+ "description": "Returns a new object — neither input is mutated.",
629
+ "code": "mergeDeep({ a: 1, b: { c: 2 } }, { b: { d: 3 }, e: 4 })\n// => { a: 1, b: { c: 2, d: 3 }, e: 4 }"
630
+ }
631
+ ],
632
+ "sourceFile": "mergeDeep.ts"
633
+ },
661
634
  {
662
635
  "name": "omit",
663
636
  "kind": "function",
@@ -752,12 +725,12 @@
752
725
  {
753
726
  "name": "pick",
754
727
  "kind": "function",
755
- "description": "Creates a new object with only the specified keys.",
728
+ "description": "Creates a new object with only the specified keys.\nKeys that are prototype-polluting strings (`__proto__`, `constructor`, `prototype`) are\nsilently skipped.",
756
729
  "since": "2.0.0",
757
730
  "signatures": [
758
731
  {
759
732
  "signature": "pick<T extends Record<string, unknown>, K extends string | number | symbol>(obj: T, keys: readonly K[]): Pick<T, K>",
760
- "description": "Creates a new object with only the specified keys.",
733
+ "description": "Creates a new object with only the specified keys.\nKeys that are prototype-polluting strings (`__proto__`, `constructor`, `prototype`) are\nsilently skipped.",
761
734
  "params": [
762
735
  {
763
736
  "name": "obj",
@@ -787,7 +760,7 @@
787
760
  },
788
761
  {
789
762
  "signature": "pick(obj: undefined, keys: readonly string[]): undefined",
790
- "description": "Creates a new object with only the specified keys.",
763
+ "description": "Creates a new object with only the specified keys.\nKeys that are prototype-polluting strings (`__proto__`, `constructor`, `prototype`) are\nsilently skipped.",
791
764
  "params": [
792
765
  {
793
766
  "name": "obj",
@@ -807,7 +780,7 @@
807
780
  },
808
781
  {
809
782
  "signature": "pick(obj: null, keys: readonly string[]): null",
810
- "description": "Creates a new object with only the specified keys.",
783
+ "description": "Creates a new object with only the specified keys.\nKeys that are prototype-polluting strings (`__proto__`, `constructor`, `prototype`) are\nsilently skipped.",
811
784
  "params": [
812
785
  {
813
786
  "name": "obj",
@@ -981,37 +954,12 @@
981
954
  {
982
955
  "name": "set",
983
956
  "kind": "function",
984
- "description": "Sets a value in an object at the given path, creating intermediate objects as needed.\n\n**Three path forms are supported:**\n\n1. **Dot notation** (`string`) — segments split on `.` are kept as-is string keys.\n `\"layers.1.name\"` → keys `[\"layers\", \"1\", \"name\"]` (all strings, including `\"1\"`).\n\n2. **Bracket notation** (`string`) — `[n]` segments are parsed as numeric keys.\n `\"layers[1].name\"` → keys `[\"layers\", 1, \"name\"]` (index `1` becomes a number).\n Dot and bracket can be mixed freely: `\"a[0].b[2].c\"`.\n\n3. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables full key-type control, including symbols:\n `[\"layers\", 1, Symbol('id')]`.\n\nIntermediate nodes that are absent, `null`, or not an object are replaced with `{}`.\nAny path containing a string segment equal to `__proto__`, `constructor`, or `prototype`\nis rejected and the original object is returned unchanged (prototype-pollution guard).",
957
+ "description": "Sets a value in an object at the given path, creating intermediate objects as needed.\n\n**Two path forms are supported:**\n\n1. **String path** — dot notation and bracket notation, mixed freely.\n - Dot segments are always string keys: `'layers.1.name'` → keys `['layers', '1', 'name']`.\n - Bracket segments are always number keys: `'layers[1].name'` → keys `['layers', 1, 'name']`.\n - String literal paths give **full compile-time type inference** on the return type.\n - Dynamic (non-literal) strings return `T` (same object type).\n\n2. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables symbol-keyed access and precise return-type inference.\n\nBoth forms support **all objects** (plain objects, arrays, class instances).\nSymbol keys are only reachable via the key-array form.\n\nIntermediate nodes that are absent, `null`, or not an object are replaced with `{}`.\nAny path containing a string segment equal to `__proto__`, `constructor`, or `prototype`\nis rejected and the original object is returned unchanged (prototype-pollution guard).",
985
958
  "since": "1.9.0",
986
959
  "signatures": [
987
960
  {
988
- "signature": "set(obj: Record<string, unknown>, path: string, value: unknown): Record<string, unknown>",
989
- "description": "Sets a value in an object at the given path, creating intermediate objects as needed.\n\n**Three path forms are supported:**\n\n1. **Dot notation** (`string`) — segments split on `.` are kept as-is string keys.\n `\"layers.1.name\"` → keys `[\"layers\", \"1\", \"name\"]` (all strings, including `\"1\"`).\n\n2. **Bracket notation** (`string`) — `[n]` segments are parsed as numeric keys.\n `\"layers[1].name\"` → keys `[\"layers\", 1, \"name\"]` (index `1` becomes a number).\n Dot and bracket can be mixed freely: `\"a[0].b[2].c\"`.\n\n3. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables full key-type control, including symbols:\n `[\"layers\", 1, Symbol('id')]`.\n\nIntermediate nodes that are absent, `null`, or not an object are replaced with `{}`.\nAny path containing a string segment equal to `__proto__`, `constructor`, or `prototype`\nis rejected and the original object is returned unchanged (prototype-pollution guard).",
990
- "params": [
991
- {
992
- "name": "obj",
993
- "type": "Record<string, unknown>",
994
- "description": "The object to mutate"
995
- },
996
- {
997
- "name": "path",
998
- "type": "string",
999
- "description": "Dot/bracket-notation string or explicit `PropertyKey[]`"
1000
- },
1001
- {
1002
- "name": "value",
1003
- "type": "unknown",
1004
- "description": "Value to assign at the path"
1005
- }
1006
- ],
1007
- "returns": {
1008
- "type": "Record<string, unknown>",
1009
- "description": "The mutated object (same reference)"
1010
- }
1011
- },
1012
- {
1013
- "signature": "set<T extends object, Path extends readonly PropertyKey[], V extends unknown>(obj: T, path: Path, value: V): DeepSet<T, Path, V>",
1014
- "description": "Sets a value in an object at the given path, creating intermediate objects as needed.\n\n**Three path forms are supported:**\n\n1. **Dot notation** (`string`) — segments split on `.` are kept as-is string keys.\n `\"layers.1.name\"` → keys `[\"layers\", \"1\", \"name\"]` (all strings, including `\"1\"`).\n\n2. **Bracket notation** (`string`) — `[n]` segments are parsed as numeric keys.\n `\"layers[1].name\"` → keys `[\"layers\", 1, \"name\"]` (index `1` becomes a number).\n Dot and bracket can be mixed freely: `\"a[0].b[2].c\"`.\n\n3. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables full key-type control, including symbols:\n `[\"layers\", 1, Symbol('id')]`.\n\nIntermediate nodes that are absent, `null`, or not an object are replaced with `{}`.\nAny path containing a string segment equal to `__proto__`, `constructor`, or `prototype`\nis rejected and the original object is returned unchanged (prototype-pollution guard).",
961
+ "signature": "set<T extends object, P extends string | readonly PropertyKey[], V extends unknown>(obj: T, path: P, value: V): conditional",
962
+ "description": "Sets a value in an object at the given path, creating intermediate objects as needed.\n\n**Two path forms are supported:**\n\n1. **String path** — dot notation and bracket notation, mixed freely.\n - Dot segments are always string keys: `'layers.1.name'` → keys `['layers', '1', 'name']`.\n - Bracket segments are always number keys: `'layers[1].name'` → keys `['layers', 1, 'name']`.\n - String literal paths give **full compile-time type inference** on the return type.\n - Dynamic (non-literal) strings return `T` (same object type).\n\n2. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,\n no parsing performed. Enables symbol-keyed access and precise return-type inference.\n\nBoth forms support **all objects** (plain objects, arrays, class instances).\nSymbol keys are only reachable via the key-array form.\n\nIntermediate nodes that are absent, `null`, or not an object are replaced with `{}`.\nAny path containing a string segment equal to `__proto__`, `constructor`, or `prototype`\nis rejected and the original object is returned unchanged (prototype-pollution guard).",
1015
963
  "params": [
1016
964
  {
1017
965
  "name": "obj",
@@ -1020,8 +968,8 @@
1020
968
  },
1021
969
  {
1022
970
  "name": "path",
1023
- "type": "Path",
1024
- "description": "Dot/bracket-notation string or explicit `PropertyKey[]`"
971
+ "type": "P",
972
+ "description": "Dot/bracket-notation string literal or explicit `PropertyKey[]`"
1025
973
  },
1026
974
  {
1027
975
  "name": "value",
@@ -1030,8 +978,8 @@
1030
978
  }
1031
979
  ],
1032
980
  "returns": {
1033
- "type": "DeepSet<T, Path, V>",
1034
- "description": "The mutated object (same reference)"
981
+ "type": "conditional",
982
+ "description": "The mutated object (same reference, narrowed type)"
1035
983
  },
1036
984
  "typeParameters": [
1037
985
  {
@@ -1039,8 +987,8 @@
1039
987
  "constraint": "object"
1040
988
  },
1041
989
  {
1042
- "name": "Path",
1043
- "constraint": "readonly PropertyKey[]"
990
+ "name": "P",
991
+ "constraint": "string | readonly PropertyKey[]"
1044
992
  },
1045
993
  {
1046
994
  "name": "V",