@helpers4/object 2.0.0-alpha.9 → 2.0.0-beta.3

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/llms.txt ADDED
@@ -0,0 +1,804 @@
1
+ # @helpers4/object
2
+
3
+ > Tree-shakable TypeScript utility functions for the `object` domain.
4
+ > Package: `@helpers4/object` — Version: 2.0.0-beta.3
5
+ > License: LGPL-3.0-or-later
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ npm install @helpers4/object
11
+ # or
12
+ pnpm add @helpers4/object
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```typescript
18
+ import { compact, deepClone, deepMerge, ... } from '@helpers4/object';
19
+ ```
20
+
21
+ ## Functions
22
+
23
+ | Function | Description |
24
+ |---|---|
25
+ | `compact` | Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `""`, `NaN`) from an objec |
26
+ | `deepClone` | Creates a deep copy of an object or array |
27
+ | `deepMerge` | Merges two or more objects deeply |
28
+ | `diff` | Structural object diff. Returns `true` when both inputs are deeply equal, otherwise a DiffResult de |
29
+ | `equalsDeep` | Recursive structural object equality. Boolean wrapper around diff \u2014 returns `true` when the tw |
30
+ | `equalsShallow` | One-level (shallow) object equality. Two objects are equal when they share the exact same set of ow |
31
+ | `get` | Gets a value from an object using a dot-notated path |
32
+ | `groupBy` | Groups an array of items by a key derived from each item. A thin, typed wrapper around `Object.grou |
33
+ | `invert` | Returns a new object with keys and values swapped. If multiple keys share the same value, the last o |
34
+ | `map` | Transforms the values and/or keys of a plain object in a single pass. Both callbacks are optional a |
35
+ | `omit` | Creates a new object without the specified keys. |
36
+ | `pick` | Creates a new object with only the specified keys. |
37
+ | `removeUndefinedNull` | Remove null and undefined values from an object. |
38
+ | `safeJsonParse` | Parses a JSON string, returning `null` (or a fallback) on any parse failure. Unlike `JSON.parse`, t |
39
+ | `set` | Sets a value in an object using a dot-notated path |
40
+
41
+ ---
42
+
43
+ ## API Reference
44
+
45
+ ### `compact`
46
+
47
+ Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `""`, `NaN`) from an object.
48
+
49
+ ```typescript
50
+ import { compact } from '@helpers4/object';
51
+
52
+ compact<T extends Record<string, unknown>>(obj: T): Partial<T>
53
+ ```
54
+
55
+ **Parameters:**
56
+
57
+ - `obj: T` — The source object
58
+
59
+ **Returns:** `Partial<T>` — A new object containing only entries with truthy values
60
+
61
+ ```typescript
62
+ import { compact } from '@helpers4/object';
63
+
64
+ compact(obj: undefined): undefined
65
+ ```
66
+
67
+ **Parameters:**
68
+
69
+ - `obj: undefined` — The source object
70
+
71
+ **Returns:** `undefined` — A new object containing only entries with truthy values
72
+
73
+ ```typescript
74
+ import { compact } from '@helpers4/object';
75
+
76
+ compact(obj: null): null
77
+ ```
78
+
79
+ **Parameters:**
80
+
81
+ - `obj: null` — The source object
82
+
83
+ **Returns:** `null` — A new object containing only entries with truthy values
84
+
85
+ **Examples:**
86
+
87
+ *Remove falsy values from object*
88
+
89
+ Removes all entries with falsy values (false, null, undefined, 0, "", NaN).
90
+
91
+ ```typescript
92
+ compact({ a: 1, b: null, c: '', d: 0, e: 'hello' })
93
+ // => { a: 1, e: 'hello' }
94
+ ```
95
+
96
+ *Clean up API response*
97
+
98
+ Useful to strip empty or missing fields before sending data.
99
+
100
+ ```typescript
101
+ compact({ name: 'Alice', email: '', age: 0, role: 'admin' })
102
+ // => { name: 'Alice', role: 'admin' }
103
+ ```
104
+
105
+ ---
106
+
107
+ ### `deepClone`
108
+
109
+ Creates a deep copy of an object or array
110
+
111
+ ```typescript
112
+ import { deepClone } from '@helpers4/object';
113
+
114
+ deepClone<T>(obj: T): T
115
+ ```
116
+
117
+ **Parameters:**
118
+
119
+ - `obj: T` — The object to clone
120
+
121
+ **Returns:** `T` — Deep cloned object
122
+
123
+ **Examples:**
124
+
125
+ *Clone a nested object*
126
+
127
+ Creates a deep copy — modifying the clone does not affect the original.
128
+
129
+ ```typescript
130
+ const original = { a: { b: 1 } };
131
+ const cloned = deepClone(original);
132
+ cloned.a.b = 2;
133
+ // original.a.b is still 1
134
+ ```
135
+
136
+ ---
137
+
138
+ ### `deepMerge`
139
+
140
+ Merges two or more objects deeply
141
+
142
+ ```typescript
143
+ import { deepMerge } from '@helpers4/object';
144
+
145
+ deepMerge<T extends Record<string, unknown>>(target: T, sources: Record<string, unknown>[]): T
146
+ ```
147
+
148
+ **Parameters:**
149
+
150
+ - `target: T` — The target object
151
+ - `sources: Record<string, unknown>[]` — The source objects to merge
152
+
153
+ **Returns:** `T` — The merged object
154
+
155
+ ```typescript
156
+ import { deepMerge } from '@helpers4/object';
157
+
158
+ deepMerge(target: undefined, sources: Record<string, unknown>[]): undefined
159
+ ```
160
+
161
+ **Parameters:**
162
+
163
+ - `target: undefined` — The target object
164
+ - `sources: Record<string, unknown>[]` — The source objects to merge
165
+
166
+ **Returns:** `undefined` — The merged object
167
+
168
+ ```typescript
169
+ import { deepMerge } from '@helpers4/object';
170
+
171
+ deepMerge(target: null, sources: Record<string, unknown>[]): null
172
+ ```
173
+
174
+ **Parameters:**
175
+
176
+ - `target: null` — The target object
177
+ - `sources: Record<string, unknown>[]` — The source objects to merge
178
+
179
+ **Returns:** `null` — The merged object
180
+
181
+ **Examples:**
182
+
183
+ *Merge two objects deeply*
184
+
185
+ Recursively merges source properties into the target object.
186
+
187
+ ```typescript
188
+ deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 }, e: 4 })
189
+ // => { a: 1, b: { c: 2, d: 3 }, e: 4 }
190
+ ```
191
+
192
+ ---
193
+
194
+ ### `diff`
195
+
196
+ Structural object diff.
197
+
198
+ Returns `true` when both inputs are deeply equal, otherwise a
199
+ DiffResult describing the differences key by key.
200
+
201
+ Comparison rules:
202
+ - Same reference \u2192 `true`.
203
+ - Either side is `null`/`undefined` (and not both) \u2192 `false`.
204
+ - Both `Date` \u2192 epoch comparison.
205
+ - Both arrays \u2192 compared with `array/equalsDeep` (leaf, no diff drill-down).
206
+ - Special objects (Map, Set, RegExp, Promise, class instances\u2026) \u2192 reference equality.
207
+ - Plain objects \u2192 key-by-key, recursing up to `options.depth` levels.
208
+ - Mixed types (e.g. array vs object, Date vs object) \u2192 `false`.
209
+
210
+ For a boolean wrapper see equalsDeep from this category.
211
+ For a one-level boolean check see equalsShallow from this category.
212
+
213
+ ```typescript
214
+ import { diff } from '@helpers4/object';
215
+
216
+ diff(objA: object | null | undefined, objB: object | null | undefined, options: DiffOptions): boolean | DiffResult
217
+ ```
218
+
219
+ **Parameters:**
220
+
221
+ - `objA: object | null | undefined` — First value (object, `null`, or `undefined`).
222
+ - `objB: object | null | undefined` — Second value (object, `null`, or `undefined`).
223
+ - `options: DiffOptions` (default: `{}`) — See DiffOptions.
224
+
225
+ **Returns:** `boolean | DiffResult` — `true` when equal, otherwise a DiffResult, or `false` for incompatible types.
226
+
227
+ **Examples:**
228
+
229
+ *Compare nested objects*
230
+
231
+ Deeply compares two objects, returning true when they are structurally equal.
232
+
233
+ ```typescript
234
+ diff({ a: { b: 1 } }, { a: { b: 1 } })
235
+ // => true
236
+ ```
237
+
238
+ *Detect deep differences*
239
+
240
+ Returns a detailed diff object when nested values differ.
241
+
242
+ ```typescript
243
+ diff({ a: { b: 1 } }, { a: { b: 2 } })
244
+ // => { a: { b: false } }
245
+ ```
246
+
247
+ ---
248
+
249
+ ### `equalsDeep`
250
+
251
+ Recursive structural object equality.
252
+
253
+ Boolean wrapper around diff \u2014 returns `true` when the two values
254
+ are deeply equal according to the same rules. Use this when you only
255
+ need a yes/no answer; use diff when you also need to know
256
+ *what* differs.
257
+
258
+ For a one-level boolean check use equalsShallow.
259
+
260
+ ```typescript
261
+ import { equalsDeep } from '@helpers4/object';
262
+
263
+ equalsDeep(objA: object | null | undefined, objB: object | null | undefined): boolean
264
+ ```
265
+
266
+ **Parameters:**
267
+
268
+ - `objA: object | null | undefined` — First value (object, `null`, or `undefined`).
269
+ - `objB: object | null | undefined` — Second value (object, `null`, or `undefined`).
270
+
271
+ **Returns:** `boolean` — `true` if both inputs are deeply equal, `false` otherwise.
272
+
273
+ **Examples:**
274
+
275
+ *Compare nested objects*
276
+
277
+ Recursive structural equality. Returns true when the two values are deeply equal.
278
+
279
+ ```typescript
280
+ equalsDeep({ a: { b: 1 } }, { a: { b: 1 } })
281
+ // => true
282
+ ```
283
+
284
+ *Detect deep differences*
285
+
286
+ Returns false when nested values differ.
287
+
288
+ ```typescript
289
+ equalsDeep({ a: { b: 1 } }, { a: { b: 2 } })
290
+ // => false
291
+ ```
292
+
293
+ ---
294
+
295
+ ### `equalsShallow`
296
+
297
+ One-level (shallow) object equality.
298
+
299
+ Two objects are equal when they share the exact same set of own
300
+ enumerable string keys and each pair of values satisfies strict equality
301
+ (`===`). No recursion: nested objects/arrays are compared by reference.
302
+
303
+ Falls back to strict equality when either input is `null`, `undefined`
304
+ or not an object \u2014 so primitives match if and only if they are `===`.
305
+ Arrays are not supported; they always return `false` (unless identical
306
+ references). Use `array/equalsShallow` instead.
307
+
308
+ For recursive structural comparison use equalsDeep. For a diff
309
+ structure use diff.
310
+
311
+ ```typescript
312
+ import { equalsShallow } from '@helpers4/object';
313
+
314
+ equalsShallow(objA: unknown, objB: unknown): boolean
315
+ ```
316
+
317
+ **Parameters:**
318
+
319
+ - `objA: unknown` — First value to compare
320
+ - `objB: unknown` — Second value to compare
321
+
322
+ **Returns:** `boolean` — `true` if values are shallowly equal, `false` otherwise.
323
+
324
+ **Examples:**
325
+
326
+ *Compare two equal objects*
327
+
328
+ Uses JSON.stringify for a fast comparison.
329
+
330
+ ```typescript
331
+ equalsShallow({ a: 1, b: 2 }, { a: 1, b: 2 })
332
+ // => true
333
+ ```
334
+
335
+ ---
336
+
337
+ ### `get`
338
+
339
+ Gets a value from an object using a dot-notated path
340
+
341
+ ```typescript
342
+ import { get } from '@helpers4/object';
343
+
344
+ get<T = unknown>(obj: unknown, path: string, defaultValue?: T): T | undefined
345
+ ```
346
+
347
+ **Parameters:**
348
+
349
+ - `obj: unknown` — The object to get value from
350
+ - `path: string` — The dot-notated path (e.g., 'a.b.c')
351
+ - `defaultValue?: T` — Default value if path doesn't exist
352
+
353
+ **Returns:** `T | undefined` — The value at the path or default value
354
+
355
+ **Examples:**
356
+
357
+ *Access a nested property*
358
+
359
+ Uses a dot-notated path to retrieve a deeply nested value.
360
+
361
+ ```typescript
362
+ get({ a: { b: { c: 42 } } }, 'a.b.c')
363
+ // => 42
364
+ ```
365
+
366
+ *Return default for missing path*
367
+
368
+ Returns the default value when the path does not exist.
369
+
370
+ ```typescript
371
+ get({ a: 1 }, 'b.c', 'default')
372
+ // => 'default'
373
+ ```
374
+
375
+ ---
376
+
377
+ ### `groupBy`
378
+
379
+ Groups an array of items by a key derived from each item.
380
+
381
+ A thin, typed wrapper around `Object.groupBy` (ES2024) that works on
382
+ older targets and provides stricter return-type inference.
383
+
384
+ ```typescript
385
+ import { groupBy } from '@helpers4/object';
386
+
387
+ groupBy<T, K extends PropertyKey>(items: readonly T[], keyFn: function): Partial<Record<K, T[]>>
388
+ ```
389
+
390
+ **Parameters:**
391
+
392
+ - `items: readonly T[]` — The array to group
393
+ - `keyFn: function` — Function that returns the group key for each item
394
+
395
+ **Returns:** `Partial<Record<K, T[]>>` — A record mapping each key to the array of items with that key
396
+
397
+ **Examples:**
398
+
399
+ *Group numbers by parity*
400
+
401
+ Groups elements by the string key returned by the callback.
402
+
403
+ ```typescript
404
+ groupBy([1, 2, 3, 4], n => n % 2 === 0 ? 'even' : 'odd')
405
+ // => { odd: [1, 3], even: [2, 4] }
406
+ ```
407
+
408
+ *Group objects by a property*
409
+
410
+ Use a property accessor as the grouping key.
411
+
412
+ ```typescript
413
+ const users = [
414
+ { name: 'Alice', role: 'admin' },
415
+ { name: 'Bob', role: 'user' },
416
+ { name: 'Carol', role: 'admin' },
417
+ ];
418
+ groupBy(users, u => u.role)
419
+ // => { admin: [{...Alice}, {...Carol}], user: [{...Bob}] }
420
+ ```
421
+
422
+ ---
423
+
424
+ ### `invert`
425
+
426
+ Returns a new object with keys and values swapped.
427
+ If multiple keys share the same value, the last one wins.
428
+
429
+ ```typescript
430
+ import { invert } from '@helpers4/object';
431
+
432
+ invert<K extends string, V extends PropertyKey>(obj: Record<K, V>): Record<V, K>
433
+ ```
434
+
435
+ **Parameters:**
436
+
437
+ - `obj: Record<K, V>` — The object whose keys and values are to be swapped
438
+
439
+ **Returns:** `Record<V, K>` — A new object with values as keys and original keys as values
440
+
441
+ **Examples:**
442
+
443
+ *Swap keys and values*
444
+
445
+ Returns a new object with keys and values swapped.
446
+
447
+ ```typescript
448
+ invert({ a: 'x', b: 'y', c: 'z' })
449
+ // => { x: 'a', y: 'b', z: 'c' }
450
+ ```
451
+
452
+ *Build a reverse lookup map*
453
+
454
+ Useful when you have a code-to-label map and need label-to-code.
455
+
456
+ ```typescript
457
+ const STATUS_LABELS = { 200: 'OK', 404: 'Not Found', 500: 'Internal Server Error' };
458
+ const LABEL_TO_CODE = invert(STATUS_LABELS);
459
+
460
+ LABEL_TO_CODE['OK']; // => '200'
461
+ ```
462
+
463
+ ---
464
+
465
+ ### `map`
466
+
467
+ Transforms the values and/or keys of a plain object in a single pass.
468
+
469
+ Both callbacks are optional and default to identity (no transformation).
470
+ When `mapValue` is omitted the original values are preserved;
471
+ when `mapKey` is omitted the original keys are preserved.
472
+
473
+ Note: if two different keys map to the same output key the last one wins
474
+ (insertion order).
475
+
476
+ ```typescript
477
+ import { map } from '@helpers4/object';
478
+
479
+ map<TObj extends Record<string, unknown>, TVal = indexedAccess, TKey extends PropertyKey = keyof TObj>(obj: TObj, mapValue?: function, mapKey?: function): Record<TKey, TVal>
480
+ ```
481
+
482
+ **Parameters:**
483
+
484
+ - `obj: TObj` — The source object
485
+ - `mapValue?: function` — Callback called with `(value, key)` for each entry.
486
+ Defaults to identity.
487
+ - `mapKey?: function` — Callback called with `(key, value)` for each entry.
488
+ Defaults to identity.
489
+
490
+ **Returns:** `Record<TKey, TVal>` — A new object with transformed keys and/or values
491
+
492
+ **Examples:**
493
+
494
+ *Transform values*
495
+
496
+ Maps each value of an object through a transform function.
497
+
498
+ ```typescript
499
+ map({ a: 1, b: 2 }, v => v * 10)
500
+ // => { a: 10, b: 20 }
501
+ ```
502
+
503
+ *Transform keys*
504
+
505
+ Maps each key of an object through a transform function.
506
+
507
+ ```typescript
508
+ map({ a: 1, b: 2 }, undefined, k => k.toUpperCase())
509
+ // => { A: 1, B: 2 }
510
+ ```
511
+
512
+ *Transform both keys and values in a single pass*
513
+
514
+ Provide both a value mapper and a key mapper to rewrite the whole object.
515
+
516
+ ```typescript
517
+ map(
518
+ { price: 100, discount: 20 },
519
+ v => v / 100,
520
+ k => `${k}Ratio`
521
+ )
522
+ // => { priceRatio: 1, discountRatio: 0.2 }
523
+ ```
524
+
525
+ ---
526
+
527
+ ### `omit`
528
+
529
+ Creates a new object without the specified keys.
530
+
531
+ ```typescript
532
+ import { omit } from '@helpers4/object';
533
+
534
+ omit<T extends Record<string, unknown>, K extends string | number | symbol>(obj: T, keys: readonly K[]): Omit<T, K>
535
+ ```
536
+
537
+ **Parameters:**
538
+
539
+ - `obj: T` — The source object
540
+ - `keys: readonly K[]` — The keys to omit
541
+
542
+ **Returns:** `Omit<T, K>` — A new object without the omitted keys
543
+
544
+ ```typescript
545
+ import { omit } from '@helpers4/object';
546
+
547
+ omit(obj: undefined, keys: readonly string[]): undefined
548
+ ```
549
+
550
+ **Parameters:**
551
+
552
+ - `obj: undefined` — The source object
553
+ - `keys: readonly string[]` — The keys to omit
554
+
555
+ **Returns:** `undefined` — A new object without the omitted keys
556
+
557
+ ```typescript
558
+ import { omit } from '@helpers4/object';
559
+
560
+ omit(obj: null, keys: readonly string[]): null
561
+ ```
562
+
563
+ **Parameters:**
564
+
565
+ - `obj: null` — The source object
566
+ - `keys: readonly string[]` — The keys to omit
567
+
568
+ **Returns:** `null` — A new object without the omitted keys
569
+
570
+ **Examples:**
571
+
572
+ *Omit specific keys*
573
+
574
+ Creates a new object without the specified keys.
575
+
576
+ ```typescript
577
+ omit({ a: 1, b: 2, c: 3 }, ['b'])
578
+ // => { a: 1, c: 3 }
579
+ ```
580
+
581
+ *Remove sensitive fields*
582
+
583
+ Useful to strip sensitive data before sending to client.
584
+
585
+ ```typescript
586
+ const user = { id: 1, name: 'Alice', password: 'secret', token: 'abc123' };
587
+ omit(user, ['password', 'token'])
588
+ // => { id: 1, name: 'Alice' }
589
+ ```
590
+
591
+ ---
592
+
593
+ ### `pick`
594
+
595
+ Creates a new object with only the specified keys.
596
+
597
+ ```typescript
598
+ import { pick } from '@helpers4/object';
599
+
600
+ pick<T extends Record<string, unknown>, K extends string | number | symbol>(obj: T, keys: readonly K[]): Pick<T, K>
601
+ ```
602
+
603
+ **Parameters:**
604
+
605
+ - `obj: T` — The source object
606
+ - `keys: readonly K[]` — The keys to pick
607
+
608
+ **Returns:** `Pick<T, K>` — A new object with only the picked keys
609
+
610
+ ```typescript
611
+ import { pick } from '@helpers4/object';
612
+
613
+ pick(obj: undefined, keys: readonly string[]): undefined
614
+ ```
615
+
616
+ **Parameters:**
617
+
618
+ - `obj: undefined` — The source object
619
+ - `keys: readonly string[]` — The keys to pick
620
+
621
+ **Returns:** `undefined` — A new object with only the picked keys
622
+
623
+ ```typescript
624
+ import { pick } from '@helpers4/object';
625
+
626
+ pick(obj: null, keys: readonly string[]): null
627
+ ```
628
+
629
+ **Parameters:**
630
+
631
+ - `obj: null` — The source object
632
+ - `keys: readonly string[]` — The keys to pick
633
+
634
+ **Returns:** `null` — A new object with only the picked keys
635
+
636
+ **Examples:**
637
+
638
+ *Pick specific keys*
639
+
640
+ Creates a new object with only the specified keys.
641
+
642
+ ```typescript
643
+ pick({ a: 1, b: 2, c: 3 }, ['a', 'c'])
644
+ // => { a: 1, c: 3 }
645
+ ```
646
+
647
+ *Extract user fields*
648
+
649
+ Useful to select only the fields you need from an object.
650
+
651
+ ```typescript
652
+ const user = { id: 1, name: 'Alice', email: 'alice@example.com', password: 'secret' };
653
+ pick(user, ['id', 'name', 'email'])
654
+ // => { id: 1, name: 'Alice', email: 'alice@example.com' }
655
+ ```
656
+
657
+ ---
658
+
659
+ ### `removeUndefinedNull`
660
+
661
+ Remove null and undefined values from an object.
662
+
663
+ ```typescript
664
+ import { removeUndefinedNull } from '@helpers4/object';
665
+
666
+ removeUndefinedNull<T extends Record<string, string | number | boolean | null | undefined>>(obj: T): Partial<T>
667
+ ```
668
+
669
+ **Parameters:**
670
+
671
+ - `obj: T` — an object
672
+
673
+ **Returns:** `Partial<T>` — A shallow copy of the object without null or undefined values
674
+
675
+ ```typescript
676
+ import { removeUndefinedNull } from '@helpers4/object';
677
+
678
+ removeUndefinedNull(obj: null): null
679
+ ```
680
+
681
+ **Parameters:**
682
+
683
+ - `obj: null` — a null object
684
+
685
+ **Returns:** `null` — null
686
+
687
+ ```typescript
688
+ import { removeUndefinedNull } from '@helpers4/object';
689
+
690
+ removeUndefinedNull(obj: undefined): undefined
691
+ ```
692
+
693
+ **Parameters:**
694
+
695
+ - `obj: undefined` — an undefined object
696
+
697
+ **Returns:** `undefined` — undefined
698
+
699
+ **Examples:**
700
+
701
+ *Strip null and undefined values*
702
+
703
+ Returns a shallow copy of the object without null or undefined properties.
704
+
705
+ ```typescript
706
+ removeUndefinedNull({ a: 1, b: null, c: undefined, d: 'ok' })
707
+ // => { a: 1, d: 'ok' }
708
+ ```
709
+
710
+ ---
711
+
712
+ ### `safeJsonParse`
713
+
714
+ Parses a JSON string, returning `null` (or a fallback) on any parse failure.
715
+
716
+ Unlike `JSON.parse`, this never throws. Invalid JSON strings and other
717
+ parsing edge-cases resolve to `null` or the provided `fallback`.
718
+
719
+ ```typescript
720
+ import { safeJsonParse } from '@helpers4/object';
721
+
722
+ safeJsonParse<T>(input: string): T | null
723
+ ```
724
+
725
+ **Parameters:**
726
+
727
+ - `input: string` — The JSON string to parse.
728
+
729
+ **Returns:** `T | null` — The parsed value typed as `T`, or `fallback` on failure.
730
+
731
+ ```typescript
732
+ import { safeJsonParse } from '@helpers4/object';
733
+
734
+ safeJsonParse<T>(input: string, fallback: T): T
735
+ ```
736
+
737
+ **Parameters:**
738
+
739
+ - `input: string` — The JSON string to parse.
740
+ - `fallback: T` — Value returned on failure. Defaults to `null` when omitted.
741
+
742
+ **Returns:** `T` — The parsed value typed as `T`, or `fallback` on failure.
743
+
744
+ **Examples:**
745
+
746
+ *Parse valid JSON*
747
+
748
+ Returns the parsed value when the input is valid JSON.
749
+
750
+ ```typescript
751
+ safeJsonParse<{ a: number }>('{"a":1}')
752
+ // => { a: 1 }
753
+ ```
754
+
755
+ *Return null on invalid input*
756
+
757
+ Returns null instead of throwing when JSON is malformed.
758
+
759
+ ```typescript
760
+ safeJsonParse('invalid')
761
+ // => null
762
+ ```
763
+
764
+ *Use a fallback value*
765
+
766
+ Returns the provided fallback when parsing fails.
767
+
768
+ ```typescript
769
+ safeJsonParse('invalid', [])
770
+ // => []
771
+ ```
772
+
773
+ ---
774
+
775
+ ### `set`
776
+
777
+ Sets a value in an object using a dot-notated path
778
+
779
+ ```typescript
780
+ import { set } from '@helpers4/object';
781
+
782
+ set(obj: Record<string, unknown>, path: string, value: unknown): Record<string, unknown>
783
+ ```
784
+
785
+ **Parameters:**
786
+
787
+ - `obj: Record<string, unknown>` — The object to set value in
788
+ - `path: string` — The dot-notated path (e.g., 'a.b.c')
789
+ - `value: unknown` — The value to set
790
+
791
+ **Returns:** `Record<string, unknown>` — The modified object
792
+
793
+ **Examples:**
794
+
795
+ *Set a nested property*
796
+
797
+ Creates intermediate objects as needed along the dot-notated path.
798
+
799
+ ```typescript
800
+ set({}, 'a.b.c', 42)
801
+ // => { a: { b: { c: 42 } } }
802
+ ```
803
+
804
+ ---