ts-data-forge 1.0.0 → 1.0.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/README.md +1 -1
- package/dist/array/array-utils.d.mts +2617 -0
- package/dist/array/array-utils.d.mts.map +1 -0
- package/dist/array/array-utils.mjs +2915 -0
- package/dist/array/array-utils.mjs.map +1 -0
- package/dist/array/index.d.mts +3 -0
- package/dist/array/index.d.mts.map +1 -0
- package/dist/array/index.mjs +3 -0
- package/dist/array/index.mjs.map +1 -0
- package/dist/array/tuple-utils.d.mts +421 -0
- package/dist/array/tuple-utils.d.mts.map +1 -0
- package/dist/array/tuple-utils.mjs +391 -0
- package/dist/array/tuple-utils.mjs.map +1 -0
- package/dist/collections/imap-mapped.d.mts +445 -0
- package/dist/collections/imap-mapped.d.mts.map +1 -0
- package/dist/collections/imap-mapped.mjs +424 -0
- package/dist/collections/imap-mapped.mjs.map +1 -0
- package/dist/collections/imap.d.mts +359 -0
- package/dist/collections/imap.d.mts.map +1 -0
- package/dist/collections/imap.mjs +338 -0
- package/dist/collections/imap.mjs.map +1 -0
- package/dist/collections/index.d.mts +7 -0
- package/dist/collections/index.d.mts.map +1 -0
- package/dist/collections/index.mjs +7 -0
- package/dist/collections/index.mjs.map +1 -0
- package/dist/collections/iset-mapped.d.mts +576 -0
- package/dist/collections/iset-mapped.d.mts.map +1 -0
- package/dist/collections/iset-mapped.mjs +522 -0
- package/dist/collections/iset-mapped.mjs.map +1 -0
- package/dist/collections/iset.d.mts +426 -0
- package/dist/collections/iset.d.mts.map +1 -0
- package/dist/collections/iset.mjs +437 -0
- package/dist/collections/iset.mjs.map +1 -0
- package/dist/collections/queue.d.mts +190 -0
- package/dist/collections/queue.d.mts.map +1 -0
- package/dist/collections/queue.mjs +317 -0
- package/dist/collections/queue.mjs.map +1 -0
- package/dist/collections/stack.d.mts +210 -0
- package/dist/collections/stack.d.mts.map +1 -0
- package/dist/collections/stack.mjs +353 -0
- package/dist/collections/stack.mjs.map +1 -0
- package/dist/expect-type.d.mts +199 -0
- package/dist/expect-type.d.mts.map +1 -0
- package/dist/expect-type.mjs +201 -0
- package/dist/expect-type.mjs.map +1 -0
- package/dist/functional/index.d.mts +5 -0
- package/dist/functional/index.d.mts.map +1 -0
- package/dist/functional/index.mjs +5 -0
- package/dist/functional/index.mjs.map +1 -0
- package/dist/functional/match.d.mts +215 -0
- package/dist/functional/match.d.mts.map +1 -0
- package/dist/functional/match.mjs +139 -0
- package/dist/functional/match.mjs.map +1 -0
- package/dist/functional/optional.d.mts +517 -0
- package/dist/functional/optional.d.mts.map +1 -0
- package/dist/functional/optional.mjs +532 -0
- package/dist/functional/optional.mjs.map +1 -0
- package/dist/functional/pipe.d.mts +185 -0
- package/dist/functional/pipe.d.mts.map +1 -0
- package/dist/functional/pipe.mjs +129 -0
- package/dist/functional/pipe.mjs.map +1 -0
- package/dist/functional/result.d.mts +796 -0
- package/dist/functional/result.d.mts.map +1 -0
- package/dist/functional/result.mjs +844 -0
- package/dist/functional/result.mjs.map +1 -0
- package/dist/globals.d.mts +38 -0
- package/dist/guard/has-key.d.mts +100 -0
- package/dist/guard/has-key.d.mts.map +1 -0
- package/dist/guard/has-key.mjs +94 -0
- package/dist/guard/has-key.mjs.map +1 -0
- package/dist/guard/index.d.mts +8 -0
- package/dist/guard/index.d.mts.map +1 -0
- package/dist/guard/index.mjs +8 -0
- package/dist/guard/index.mjs.map +1 -0
- package/dist/guard/is-non-empty-string.d.mts +106 -0
- package/dist/guard/is-non-empty-string.d.mts.map +1 -0
- package/dist/guard/is-non-empty-string.mjs +108 -0
- package/dist/guard/is-non-empty-string.mjs.map +1 -0
- package/dist/guard/is-non-null-object.d.mts +105 -0
- package/dist/guard/is-non-null-object.d.mts.map +1 -0
- package/dist/guard/is-non-null-object.mjs +108 -0
- package/dist/guard/is-non-null-object.mjs.map +1 -0
- package/dist/guard/is-primitive.d.mts +146 -0
- package/dist/guard/is-primitive.d.mts.map +1 -0
- package/dist/guard/is-primitive.mjs +161 -0
- package/dist/guard/is-primitive.mjs.map +1 -0
- package/dist/guard/is-record.d.mts +151 -0
- package/dist/guard/is-record.d.mts.map +1 -0
- package/dist/guard/is-record.mjs +155 -0
- package/dist/guard/is-record.mjs.map +1 -0
- package/dist/guard/is-type.d.mts +430 -0
- package/dist/guard/is-type.d.mts.map +1 -0
- package/dist/guard/is-type.mjs +432 -0
- package/dist/guard/is-type.mjs.map +1 -0
- package/dist/guard/key-is-in.d.mts +158 -0
- package/dist/guard/key-is-in.d.mts.map +1 -0
- package/dist/guard/key-is-in.mjs +160 -0
- package/dist/guard/key-is-in.mjs.map +1 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +61 -0
- package/dist/index.mjs.map +1 -0
- package/dist/iterator/index.d.mts +2 -0
- package/dist/iterator/index.d.mts.map +1 -0
- package/dist/iterator/index.mjs +2 -0
- package/dist/iterator/index.mjs.map +1 -0
- package/dist/iterator/range.d.mts +97 -0
- package/dist/iterator/range.d.mts.map +1 -0
- package/dist/iterator/range.mjs +130 -0
- package/dist/iterator/range.mjs.map +1 -0
- package/dist/json/index.d.mts +2 -0
- package/dist/json/index.d.mts.map +1 -0
- package/dist/json/index.mjs +2 -0
- package/dist/json/index.mjs.map +1 -0
- package/dist/json/json.d.mts +597 -0
- package/dist/json/json.d.mts.map +1 -0
- package/dist/json/json.mjs +687 -0
- package/dist/json/json.mjs.map +1 -0
- package/dist/number/branded-types/finite-number.d.mts +291 -0
- package/dist/number/branded-types/finite-number.d.mts.map +1 -0
- package/dist/number/branded-types/finite-number.mjs +296 -0
- package/dist/number/branded-types/finite-number.mjs.map +1 -0
- package/dist/number/branded-types/index.d.mts +27 -0
- package/dist/number/branded-types/index.d.mts.map +1 -0
- package/dist/number/branded-types/index.mjs +27 -0
- package/dist/number/branded-types/index.mjs.map +1 -0
- package/dist/number/branded-types/int.d.mts +242 -0
- package/dist/number/branded-types/int.d.mts.map +1 -0
- package/dist/number/branded-types/int.mjs +239 -0
- package/dist/number/branded-types/int.mjs.map +1 -0
- package/dist/number/branded-types/int16.d.mts +162 -0
- package/dist/number/branded-types/int16.d.mts.map +1 -0
- package/dist/number/branded-types/int16.mjs +141 -0
- package/dist/number/branded-types/int16.mjs.map +1 -0
- package/dist/number/branded-types/int32.d.mts +155 -0
- package/dist/number/branded-types/int32.d.mts.map +1 -0
- package/dist/number/branded-types/int32.mjs +142 -0
- package/dist/number/branded-types/int32.mjs.map +1 -0
- package/dist/number/branded-types/non-negative-finite-number.d.mts +165 -0
- package/dist/number/branded-types/non-negative-finite-number.d.mts.map +1 -0
- package/dist/number/branded-types/non-negative-finite-number.mjs +160 -0
- package/dist/number/branded-types/non-negative-finite-number.mjs.map +1 -0
- package/dist/number/branded-types/non-negative-int16.d.mts +160 -0
- package/dist/number/branded-types/non-negative-int16.d.mts.map +1 -0
- package/dist/number/branded-types/non-negative-int16.mjs +138 -0
- package/dist/number/branded-types/non-negative-int16.mjs.map +1 -0
- package/dist/number/branded-types/non-negative-int32.d.mts +156 -0
- package/dist/number/branded-types/non-negative-int32.d.mts.map +1 -0
- package/dist/number/branded-types/non-negative-int32.mjs +138 -0
- package/dist/number/branded-types/non-negative-int32.mjs.map +1 -0
- package/dist/number/branded-types/non-zero-finite-number.d.mts +154 -0
- package/dist/number/branded-types/non-zero-finite-number.d.mts.map +1 -0
- package/dist/number/branded-types/non-zero-finite-number.mjs +160 -0
- package/dist/number/branded-types/non-zero-finite-number.mjs.map +1 -0
- package/dist/number/branded-types/non-zero-int.d.mts +131 -0
- package/dist/number/branded-types/non-zero-int.d.mts.map +1 -0
- package/dist/number/branded-types/non-zero-int.mjs +128 -0
- package/dist/number/branded-types/non-zero-int.mjs.map +1 -0
- package/dist/number/branded-types/non-zero-int16.d.mts +166 -0
- package/dist/number/branded-types/non-zero-int16.d.mts.map +1 -0
- package/dist/number/branded-types/non-zero-int16.mjs +145 -0
- package/dist/number/branded-types/non-zero-int16.mjs.map +1 -0
- package/dist/number/branded-types/non-zero-int32.d.mts +158 -0
- package/dist/number/branded-types/non-zero-int32.d.mts.map +1 -0
- package/dist/number/branded-types/non-zero-int32.mjs +145 -0
- package/dist/number/branded-types/non-zero-int32.mjs.map +1 -0
- package/dist/number/branded-types/non-zero-safe-int.d.mts +148 -0
- package/dist/number/branded-types/non-zero-safe-int.d.mts.map +1 -0
- package/dist/number/branded-types/non-zero-safe-int.mjs +145 -0
- package/dist/number/branded-types/non-zero-safe-int.mjs.map +1 -0
- package/dist/number/branded-types/non-zero-uint16.d.mts +160 -0
- package/dist/number/branded-types/non-zero-uint16.d.mts.map +1 -0
- package/dist/number/branded-types/non-zero-uint16.mjs +140 -0
- package/dist/number/branded-types/non-zero-uint16.mjs.map +1 -0
- package/dist/number/branded-types/non-zero-uint32.d.mts +156 -0
- package/dist/number/branded-types/non-zero-uint32.d.mts.map +1 -0
- package/dist/number/branded-types/non-zero-uint32.mjs +140 -0
- package/dist/number/branded-types/non-zero-uint32.mjs.map +1 -0
- package/dist/number/branded-types/positive-finite-number.d.mts +171 -0
- package/dist/number/branded-types/positive-finite-number.d.mts.map +1 -0
- package/dist/number/branded-types/positive-finite-number.mjs +165 -0
- package/dist/number/branded-types/positive-finite-number.mjs.map +1 -0
- package/dist/number/branded-types/positive-int.d.mts +270 -0
- package/dist/number/branded-types/positive-int.d.mts.map +1 -0
- package/dist/number/branded-types/positive-int.mjs +257 -0
- package/dist/number/branded-types/positive-int.mjs.map +1 -0
- package/dist/number/branded-types/positive-int16.d.mts +162 -0
- package/dist/number/branded-types/positive-int16.d.mts.map +1 -0
- package/dist/number/branded-types/positive-int16.mjs +139 -0
- package/dist/number/branded-types/positive-int16.mjs.map +1 -0
- package/dist/number/branded-types/positive-int32.d.mts +158 -0
- package/dist/number/branded-types/positive-int32.d.mts.map +1 -0
- package/dist/number/branded-types/positive-int32.mjs +139 -0
- package/dist/number/branded-types/positive-int32.mjs.map +1 -0
- package/dist/number/branded-types/positive-safe-int.d.mts +152 -0
- package/dist/number/branded-types/positive-safe-int.d.mts.map +1 -0
- package/dist/number/branded-types/positive-safe-int.mjs +138 -0
- package/dist/number/branded-types/positive-safe-int.mjs.map +1 -0
- package/dist/number/branded-types/positive-uint16.d.mts +160 -0
- package/dist/number/branded-types/positive-uint16.d.mts.map +1 -0
- package/dist/number/branded-types/positive-uint16.mjs +139 -0
- package/dist/number/branded-types/positive-uint16.mjs.map +1 -0
- package/dist/number/branded-types/positive-uint32.d.mts +156 -0
- package/dist/number/branded-types/positive-uint32.d.mts.map +1 -0
- package/dist/number/branded-types/positive-uint32.mjs +139 -0
- package/dist/number/branded-types/positive-uint32.mjs.map +1 -0
- package/dist/number/branded-types/safe-int.d.mts +243 -0
- package/dist/number/branded-types/safe-int.d.mts.map +1 -0
- package/dist/number/branded-types/safe-int.mjs +240 -0
- package/dist/number/branded-types/safe-int.mjs.map +1 -0
- package/dist/number/branded-types/safe-uint.d.mts +151 -0
- package/dist/number/branded-types/safe-uint.d.mts.map +1 -0
- package/dist/number/branded-types/safe-uint.mjs +138 -0
- package/dist/number/branded-types/safe-uint.mjs.map +1 -0
- package/dist/number/branded-types/uint.d.mts +144 -0
- package/dist/number/branded-types/uint.d.mts.map +1 -0
- package/dist/number/branded-types/uint.mjs +132 -0
- package/dist/number/branded-types/uint.mjs.map +1 -0
- package/dist/number/branded-types/uint16.d.mts +157 -0
- package/dist/number/branded-types/uint16.d.mts.map +1 -0
- package/dist/number/branded-types/uint16.mjs +137 -0
- package/dist/number/branded-types/uint16.mjs.map +1 -0
- package/dist/number/branded-types/uint32.d.mts +185 -0
- package/dist/number/branded-types/uint32.d.mts.map +1 -0
- package/dist/number/branded-types/uint32.mjs +169 -0
- package/dist/number/branded-types/uint32.mjs.map +1 -0
- package/dist/number/enum/index.d.mts +3 -0
- package/dist/number/enum/index.d.mts.map +1 -0
- package/dist/number/enum/index.mjs +3 -0
- package/dist/number/enum/index.mjs.map +1 -0
- package/dist/number/enum/int8.d.mts +202 -0
- package/dist/number/enum/int8.d.mts.map +1 -0
- package/dist/number/enum/int8.mjs +296 -0
- package/dist/number/enum/int8.mjs.map +1 -0
- package/dist/number/enum/uint8.d.mts +128 -0
- package/dist/number/enum/uint8.d.mts.map +1 -0
- package/dist/number/enum/uint8.mjs +251 -0
- package/dist/number/enum/uint8.mjs.map +1 -0
- package/dist/number/index.d.mts +5 -0
- package/dist/number/index.d.mts.map +1 -0
- package/dist/number/index.mjs +31 -0
- package/dist/number/index.mjs.map +1 -0
- package/dist/number/num.d.mts +515 -0
- package/dist/number/num.d.mts.map +1 -0
- package/dist/number/num.mjs +513 -0
- package/dist/number/num.mjs.map +1 -0
- package/dist/number/refined-number-utils.d.mts +191 -0
- package/dist/number/refined-number-utils.d.mts.map +1 -0
- package/dist/number/refined-number-utils.mjs +179 -0
- package/dist/number/refined-number-utils.mjs.map +1 -0
- package/dist/object/index.d.mts +2 -0
- package/dist/object/index.d.mts.map +1 -0
- package/dist/object/index.mjs +2 -0
- package/dist/object/index.mjs.map +1 -0
- package/dist/object/object.d.mts +296 -0
- package/dist/object/object.d.mts.map +1 -0
- package/dist/object/object.mjs +295 -0
- package/dist/object/object.mjs.map +1 -0
- package/dist/others/cast-mutable.d.mts +110 -0
- package/dist/others/cast-mutable.d.mts.map +1 -0
- package/dist/others/cast-mutable.mjs +114 -0
- package/dist/others/cast-mutable.mjs.map +1 -0
- package/dist/others/cast-readonly.d.mts +189 -0
- package/dist/others/cast-readonly.d.mts.map +1 -0
- package/dist/others/cast-readonly.mjs +193 -0
- package/dist/others/cast-readonly.mjs.map +1 -0
- package/dist/others/if-then.d.mts +98 -0
- package/dist/others/if-then.d.mts.map +1 -0
- package/dist/others/if-then.mjs +100 -0
- package/dist/others/if-then.mjs.map +1 -0
- package/dist/others/index.d.mts +8 -0
- package/dist/others/index.d.mts.map +1 -0
- package/dist/others/index.mjs +8 -0
- package/dist/others/index.mjs.map +1 -0
- package/dist/others/map-nullable.d.mts +151 -0
- package/dist/others/map-nullable.d.mts.map +1 -0
- package/dist/others/map-nullable.mjs +159 -0
- package/dist/others/map-nullable.mjs.map +1 -0
- package/dist/others/memoize-function.d.mts +173 -0
- package/dist/others/memoize-function.d.mts.map +1 -0
- package/dist/others/memoize-function.mjs +189 -0
- package/dist/others/memoize-function.mjs.map +1 -0
- package/dist/others/tuple.d.mts +159 -0
- package/dist/others/tuple.d.mts.map +1 -0
- package/dist/others/tuple.mjs +161 -0
- package/dist/others/tuple.mjs.map +1 -0
- package/dist/others/unknown-to-string.d.mts +180 -0
- package/dist/others/unknown-to-string.d.mts.map +1 -0
- package/dist/others/unknown-to-string.mjs +211 -0
- package/dist/others/unknown-to-string.mjs.map +1 -0
- package/dist/tsconfig.json +1 -0
- package/package.json +16 -14
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A collection of type-safe object utility functions providing functional programming patterns
|
|
3
|
+
* for object manipulation, including pick, omit, shallow equality checks, and more.
|
|
4
|
+
*
|
|
5
|
+
* All functions maintain TypeScript type safety and support both direct and curried usage patterns
|
|
6
|
+
* for better composition with pipe operations.
|
|
7
|
+
*/
|
|
8
|
+
export declare namespace Obj {
|
|
9
|
+
/**
|
|
10
|
+
* Performs a shallow equality check on two records using a configurable equality function.
|
|
11
|
+
* Verifies that both records have the same number of entries and that for every key in the first record,
|
|
12
|
+
* the corresponding value passes the equality test with the value in the second record.
|
|
13
|
+
*
|
|
14
|
+
* @param a - The first record to compare
|
|
15
|
+
* @param b - The second record to compare
|
|
16
|
+
* @param eq - Optional equality function (defaults to Object.is for strict equality)
|
|
17
|
+
* @returns `true` if the records are shallowly equal according to the equality function, `false` otherwise
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Basic usage with default Object.is equality
|
|
22
|
+
* Obj.shallowEq({ x: 1, y: 2 }, { x: 1, y: 2 }); // true
|
|
23
|
+
* Obj.shallowEq({ x: 1 }, { x: 1, y: 2 }); // false (different number of keys)
|
|
24
|
+
* Obj.shallowEq({ x: 1 }, { x: 2 }); // false (different values)
|
|
25
|
+
* Obj.shallowEq({}, {}); // true (both empty)
|
|
26
|
+
*
|
|
27
|
+
* // String comparisons
|
|
28
|
+
* Obj.shallowEq({ a: "hello" }, { a: "hello" }); // true
|
|
29
|
+
* Obj.shallowEq({ a: "hello" }, { a: "world" }); // false
|
|
30
|
+
*
|
|
31
|
+
* // Using custom equality function
|
|
32
|
+
* const caseInsensitiveEq = (a: unknown, b: unknown) =>
|
|
33
|
+
* typeof a === 'string' && typeof b === 'string'
|
|
34
|
+
* ? a.toLowerCase() === b.toLowerCase()
|
|
35
|
+
* : a === b;
|
|
36
|
+
*
|
|
37
|
+
* Obj.shallowEq({ name: "ALICE" }, { name: "alice" }, caseInsensitiveEq); // true
|
|
38
|
+
*
|
|
39
|
+
* // Handling special values
|
|
40
|
+
* Obj.shallowEq({ x: NaN }, { x: NaN }); // true (Object.is treats NaN === NaN)
|
|
41
|
+
* Obj.shallowEq({ x: +0 }, { x: -0 }); // false (Object.is distinguishes +0 and -0)
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export const shallowEq: (a: UnknownRecord, b: UnknownRecord, eq?: (x: unknown, y: unknown) => boolean) => boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new record that contains only the specified keys from the source record.
|
|
47
|
+
* This function supports both direct usage and curried form for functional composition.
|
|
48
|
+
*
|
|
49
|
+
* **Type Safety**: Only keys that exist in the source record type are allowed,
|
|
50
|
+
* preventing runtime errors from accessing non-existent properties.
|
|
51
|
+
*
|
|
52
|
+
* @template R - The type of the input record
|
|
53
|
+
* @template Keys - The readonly array type of keys to pick from the record
|
|
54
|
+
*
|
|
55
|
+
* @param record - The source record to pick properties from
|
|
56
|
+
* @param keys - A readonly array of keys to include in the result
|
|
57
|
+
* @returns A new record containing only the specified keys and their values
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* // Direct usage
|
|
62
|
+
* const original = { a: 1, b: 2, c: 3, d: 4 };
|
|
63
|
+
* Obj.pick(original, ['a', 'c']); // { a: 1, c: 3 }
|
|
64
|
+
* Obj.pick(original, ['b']); // { b: 2 }
|
|
65
|
+
* Obj.pick(original, []); // {} (empty result)
|
|
66
|
+
*
|
|
67
|
+
* // Real-world example with user data
|
|
68
|
+
* const user = {
|
|
69
|
+
* id: 1,
|
|
70
|
+
* name: "Alice",
|
|
71
|
+
* email: "alice@example.com",
|
|
72
|
+
* password: "secret123",
|
|
73
|
+
* age: 30
|
|
74
|
+
* };
|
|
75
|
+
*
|
|
76
|
+
* // Extract public user information
|
|
77
|
+
* const publicUser = Obj.pick(user, ['id', 'name', 'email']);
|
|
78
|
+
* // Result: { id: 1, name: "Alice", email: "alice@example.com" }
|
|
79
|
+
*
|
|
80
|
+
* // Curried usage for functional composition
|
|
81
|
+
* const pickIdAndName = Obj.pick(['id', 'name'] as const);
|
|
82
|
+
* const users = [user, { id: 2, name: "Bob", email: "bob@example.com", age: 25 }];
|
|
83
|
+
* const publicUsers = users.map(pickIdAndName);
|
|
84
|
+
* // Result: [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]
|
|
85
|
+
*
|
|
86
|
+
* // Using with pipe for data transformation
|
|
87
|
+
* import { pipe } from '../functional/pipe.mjs';
|
|
88
|
+
* const result = pipe(user)
|
|
89
|
+
* .map(Obj.pick(['id', 'name']))
|
|
90
|
+
* .map(u => ({ ...u, displayName: u.name.toUpperCase() }))
|
|
91
|
+
* .value;
|
|
92
|
+
* // Result: { id: 1, name: "Alice", displayName: "ALICE" }
|
|
93
|
+
*
|
|
94
|
+
* // Type safety prevents invalid keys
|
|
95
|
+
* // Obj.pick(user, ['invalidKey']); // ❌ TypeScript error
|
|
96
|
+
* // Obj.pick(user, ['id', 'nonExistentField']); // ❌ TypeScript error
|
|
97
|
+
*
|
|
98
|
+
* // Partial key selection (when some keys might not exist)
|
|
99
|
+
* const partialUser = { id: 1, name: "Alice" } as const;
|
|
100
|
+
* const pickVisible = Obj.pick(['name', 'age']); // age might not exist
|
|
101
|
+
* const visible = pickVisible(partialUser); // { name: "Alice" } (age omitted)
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export const pick: PickFnOverload;
|
|
105
|
+
type PickFnOverload = {
|
|
106
|
+
<const R extends UnknownRecord, const Keys extends readonly (keyof R)[]>(record: R, keys: Keys): Pick<R, ArrayElement<Keys>>;
|
|
107
|
+
<const Keys extends readonly PropertyKey[]>(keys: Keys): <const R extends UnknownRecord>(record: R) => RelaxedPick<R, ArrayElement<Keys>>;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Creates a new record that excludes the specified keys from the source record.
|
|
111
|
+
* This function supports both direct usage and curried form for functional composition.
|
|
112
|
+
*
|
|
113
|
+
* **Type Safety**: Only keys that exist in the source record type are allowed,
|
|
114
|
+
* and the return type precisely reflects which properties remain after omission.
|
|
115
|
+
*
|
|
116
|
+
* @template R - The type of the input record
|
|
117
|
+
* @template Keys - The readonly array type of keys to omit from the record
|
|
118
|
+
*
|
|
119
|
+
* @param record - The source record to omit properties from
|
|
120
|
+
* @param keys - A readonly array of keys to exclude from the result
|
|
121
|
+
* @returns A new record containing all properties except the specified keys
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* // Direct usage
|
|
126
|
+
* const original = { a: 1, b: 2, c: 3, d: 4 };
|
|
127
|
+
* Obj.omit(original, ['a', 'c']); // { b: 2, d: 4 }
|
|
128
|
+
* Obj.omit(original, ['b']); // { a: 1, c: 3, d: 4 }
|
|
129
|
+
* Obj.omit(original, []); // { a: 1, b: 2, c: 3, d: 4 } (no keys omitted)
|
|
130
|
+
*
|
|
131
|
+
* // Real-world example: removing sensitive data
|
|
132
|
+
* const user = {
|
|
133
|
+
* id: 1,
|
|
134
|
+
* name: "Alice",
|
|
135
|
+
* email: "alice@example.com",
|
|
136
|
+
* password: "secret123",
|
|
137
|
+
* apiKey: "abc-def-ghi",
|
|
138
|
+
* lastLogin: new Date()
|
|
139
|
+
* };
|
|
140
|
+
*
|
|
141
|
+
* // Create safe user object for client-side
|
|
142
|
+
* const safeUser = Obj.omit(user, ['password', 'apiKey']);
|
|
143
|
+
* // Result: { id: 1, name: "Alice", email: "alice@example.com", lastLogin: Date }
|
|
144
|
+
*
|
|
145
|
+
* // Curried usage for data processing pipelines
|
|
146
|
+
* const removeSensitive = Obj.omit(['password', 'apiKey', 'ssn'] as const);
|
|
147
|
+
* const users = [user]; // array of user objects
|
|
148
|
+
* const safeUsers = users.map(removeSensitive);
|
|
149
|
+
*
|
|
150
|
+
* // Using with pipe for complex transformations
|
|
151
|
+
* import { pipe } from '../functional/pipe.mjs';
|
|
152
|
+
* const publicProfile = pipe(user)
|
|
153
|
+
* .map(Obj.omit(['password', 'apiKey']))
|
|
154
|
+
* .map(u => ({ ...u, displayName: u.name.toUpperCase() }))
|
|
155
|
+
* .value;
|
|
156
|
+
* // Result: { id: 1, name: "Alice", email: "...", lastLogin: Date, displayName: "ALICE" }
|
|
157
|
+
*
|
|
158
|
+
* // Database queries: exclude computed fields
|
|
159
|
+
* const dbUser = {
|
|
160
|
+
* id: 1,
|
|
161
|
+
* name: "Alice",
|
|
162
|
+
* email: "alice@example.com",
|
|
163
|
+
* createdAt: new Date(),
|
|
164
|
+
* updatedAt: new Date(),
|
|
165
|
+
* fullName: "Alice Johnson", // computed field
|
|
166
|
+
* isActive: true // computed field
|
|
167
|
+
* };
|
|
168
|
+
*
|
|
169
|
+
* const storableData = Obj.omit(dbUser, ['fullName', 'isActive']);
|
|
170
|
+
* // Only data that should be persisted to database
|
|
171
|
+
*
|
|
172
|
+
* // Type safety prevents invalid operations
|
|
173
|
+
* // Obj.omit(user, ['invalidKey']); // ❌ TypeScript error
|
|
174
|
+
* // Obj.omit(user, ['id', 'nonExistentField']); // ❌ TypeScript error
|
|
175
|
+
*
|
|
176
|
+
* // Handling partial omission (when some keys might not exist)
|
|
177
|
+
* const partialUser = { id: 1, name: "Alice", password: "secret" } as const;
|
|
178
|
+
* const omitCredentials = Obj.omit(['password', 'apiKey']); // apiKey might not exist
|
|
179
|
+
* const cleaned = omitCredentials(partialUser); // { id: 1, name: "Alice" }
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export const omit: OmitFnOverload;
|
|
183
|
+
type OmitFnOverload = {
|
|
184
|
+
<const R extends UnknownRecord, const Keys extends readonly (keyof R)[]>(record: R, keys: Keys): Omit<R, ArrayElement<Keys>>;
|
|
185
|
+
<const Keys extends readonly PropertyKey[]>(keys: Keys): <const R extends UnknownRecord>(record: R) => Omit<R, ArrayElement<Keys>>;
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Creates an object from an array of key-value pairs with precise TypeScript typing.
|
|
189
|
+
* This is a type-safe wrapper around `Object.fromEntries` that provides better type inference
|
|
190
|
+
* and compile-time guarantees about the resulting object structure.
|
|
191
|
+
*
|
|
192
|
+
* **Type Behavior**:
|
|
193
|
+
* - When entries is a fixed-length tuple, the exact object type is inferred
|
|
194
|
+
* - When entries has dynamic length with union key types, `Partial` is applied to prevent
|
|
195
|
+
* incorrect assumptions about which keys will be present
|
|
196
|
+
*
|
|
197
|
+
* @template Entries - The readonly array type of key-value entry tuples
|
|
198
|
+
* @param entries - An array of readonly key-value entry tuples `[key, value]`
|
|
199
|
+
* @returns An object created from the entries with precise typing
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* // Fixed entries with precise typing
|
|
204
|
+
* const fixedEntries = [
|
|
205
|
+
* ['name', 'Alice'],
|
|
206
|
+
* ['age', 30],
|
|
207
|
+
* ['active', true]
|
|
208
|
+
* ] as const;
|
|
209
|
+
*
|
|
210
|
+
* const user = Obj.fromEntries(fixedEntries);
|
|
211
|
+
* // Type: { readonly name: "Alice"; readonly age: 30; readonly active: true }
|
|
212
|
+
* // Value: { name: "Alice", age: 30, active: true }
|
|
213
|
+
*
|
|
214
|
+
* // Simple coordinate example
|
|
215
|
+
* const coordEntries = [['x', 1], ['y', 3]] as const;
|
|
216
|
+
* const point = Obj.fromEntries(coordEntries);
|
|
217
|
+
* // Type: { readonly x: 1; readonly y: 3 }
|
|
218
|
+
* // Value: { x: 1, y: 3 }
|
|
219
|
+
*
|
|
220
|
+
* // Dynamic entries with union keys
|
|
221
|
+
* const dynamicEntries: Array<['name' | 'email', string]> = [
|
|
222
|
+
* ['name', 'Alice']
|
|
223
|
+
* // email might or might not be present
|
|
224
|
+
* ];
|
|
225
|
+
* const partialUser = Obj.fromEntries(dynamicEntries);
|
|
226
|
+
* // Type: Partial<{ name: string; email: string }>
|
|
227
|
+
* // This prevents assuming both 'name' and 'email' are always present
|
|
228
|
+
*
|
|
229
|
+
* // Creating configuration objects
|
|
230
|
+
* const configEntries = [
|
|
231
|
+
* ['apiUrl', 'https://api.example.com'],
|
|
232
|
+
* ['timeout', 5000],
|
|
233
|
+
* ['retries', 3],
|
|
234
|
+
* ['debug', false]
|
|
235
|
+
* ] as const;
|
|
236
|
+
* const config = Obj.fromEntries(configEntries);
|
|
237
|
+
* // Precise types for each configuration value
|
|
238
|
+
*
|
|
239
|
+
* // Converting Maps to objects
|
|
240
|
+
* const settingsMap = new Map([
|
|
241
|
+
* ['theme', 'dark'],
|
|
242
|
+
* ['language', 'en'],
|
|
243
|
+
* ['notifications', true]
|
|
244
|
+
* ] as const);
|
|
245
|
+
* const settings = Obj.fromEntries([...settingsMap]);
|
|
246
|
+
*
|
|
247
|
+
* // Building objects from computed entries
|
|
248
|
+
* const keys = ['a', 'b', 'c'] as const;
|
|
249
|
+
* const values = [1, 2, 3] as const;
|
|
250
|
+
* const computedEntries = keys.map((k, i) => [k, values[i]] as const);
|
|
251
|
+
* const computed = Obj.fromEntries(computedEntries);
|
|
252
|
+
* // Type reflects the specific key-value associations
|
|
253
|
+
*
|
|
254
|
+
* // Error handling with validation
|
|
255
|
+
* function createUserFromEntries(entries: ReadonlyArray<readonly [string, unknown]>) {
|
|
256
|
+
* const user = Obj.fromEntries(entries);
|
|
257
|
+
* // Type is Partial<Record<string, unknown>> - safe for dynamic data
|
|
258
|
+
*
|
|
259
|
+
* if ('name' in user && typeof user.name === 'string') {
|
|
260
|
+
* // Type narrowing works correctly
|
|
261
|
+
* return { name: user.name, ...user };
|
|
262
|
+
* }
|
|
263
|
+
* throw new Error('Invalid user data');
|
|
264
|
+
* }
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
export const fromEntries: <const Entries extends readonly (readonly [PropertyKey, unknown])[]>(entries: Entries) => IsFixedLengthList<Entries> extends true ? TsVerifiedInternals.EntriesToObject<Entries> : TsVerifiedInternals.PartialIfKeyIsUnion<TsVerifiedInternals.KeysOfEntries<Entries>, Record<TsVerifiedInternals.KeysOfEntries<Entries>, TsVerifiedInternals.ValuesOfEntries<Entries>>>;
|
|
268
|
+
/**
|
|
269
|
+
* @internal
|
|
270
|
+
* Internal type utilities for the Obj module.
|
|
271
|
+
*/
|
|
272
|
+
namespace TsVerifiedInternals {
|
|
273
|
+
type RecursionLimit = 20;
|
|
274
|
+
/**
|
|
275
|
+
* - `[['x', 1], ['y', 3]]` -> `{ x: 1, y: 3 }`
|
|
276
|
+
*/
|
|
277
|
+
type EntriesToObject<Entries extends readonly (readonly [PropertyKey, unknown])[]> = Readonly<EntriesToObjectImpl<{}, Entries>>;
|
|
278
|
+
/** @internal */
|
|
279
|
+
type EntriesToObjectImpl<R, Entries extends readonly (readonly [PropertyKey, unknown])[]> = TypeEq<Entries['length'], 0> extends true ? R : EntriesToObjectImpl<R & Readonly<Record<Entries[0][0], Entries[0][1]>>, List.Tail<Entries>>;
|
|
280
|
+
/**
|
|
281
|
+
* - `['x' | 'y' | 'z', number][]]` -> `'x' | 'y' | 'z'`
|
|
282
|
+
* - `[['a' | 'b' | 'c', number], ...['x' | 'y' | 'z', number][]]` -> `'a' | 'b' |
|
|
283
|
+
* 'c' | 'x' | 'y' | 'z'`
|
|
284
|
+
*
|
|
285
|
+
* @note To handle the second example above, recursion needs to be performed on infinite-length Entries,
|
|
286
|
+
* but since the timing to stop cannot be determined, a recursion limit is set.
|
|
287
|
+
*/
|
|
288
|
+
type KeysOfEntries<Entries extends readonly (readonly [PropertyKey, unknown])[]> = KeysOfEntriesImpl<never, Entries, RecursionLimit>;
|
|
289
|
+
type KeysOfEntriesImpl<K, Entries extends readonly (readonly [PropertyKey, unknown])[], RemainingNumRecursions extends number> = TypeEq<RemainingNumRecursions, 0> extends true ? K : TypeEq<Entries['length'], 0> extends true ? K : KeysOfEntriesImpl<K | Entries[0][0], List.Tail<Entries>, Decrement<RemainingNumRecursions>>;
|
|
290
|
+
type ValuesOfEntries<Entries extends readonly (readonly [PropertyKey, unknown])[]> = ValuesOfEntriesImpl<never, Entries, RecursionLimit>;
|
|
291
|
+
type ValuesOfEntriesImpl<K, Entries extends readonly (readonly [PropertyKey, unknown])[], RemainingNumRecursions extends number> = TypeEq<RemainingNumRecursions, 0> extends true ? K : TypeEq<Entries['length'], 0> extends true ? K : ValuesOfEntriesImpl<K | Entries[0][1], List.Tail<Entries>, Decrement<RemainingNumRecursions>>;
|
|
292
|
+
type PartialIfKeyIsUnion<K, T> = IsUnion<K> extends true ? Partial<T> : T;
|
|
293
|
+
}
|
|
294
|
+
export {};
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=object.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object.d.mts","sourceRoot":"","sources":["../../src/object/object.mts"],"names":[],"mappings":"AACA;;;;;;GAMG;AACH,yBAAiB,GAAG,CAAC;IACnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACH,MAAM,CAAC,MAAM,SAAS,GACpB,GAAG,aAAa,EAChB,GAAG,aAAa,EAChB,KAAI,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,KAAK,OAAmB,KAClD,OAOF,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0DG;IACH,MAAM,CAAC,MAAM,IAAI,EAAE,cA0BC,CAAC;IAErB,KAAK,cAAc,GAAG;QACpB,CAAC,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,KAAK,CAAC,IAAI,SAAS,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EACrE,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,IAAI,GACT,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QAG/B,CAAC,KAAK,CAAC,IAAI,SAAS,SAAS,WAAW,EAAE,EACxC,IAAI,EAAE,IAAI,GACT,CAAC,KAAK,CAAC,CAAC,SAAS,aAAa,EAC/B,MAAM,EAAE,CAAC,KACN,WAAW,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;KACzC,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwEG;IACH,MAAM,CAAC,MAAM,IAAI,EAAE,cA6BC,CAAC;IAErB,KAAK,cAAc,GAAG;QACpB,CAAC,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,KAAK,CAAC,IAAI,SAAS,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EACrE,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,IAAI,GACT,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QAG/B,CAAC,KAAK,CAAC,IAAI,SAAS,SAAS,WAAW,EAAE,EACxC,IAAI,EAAE,IAAI,GACT,CAAC,KAAK,CAAC,CAAC,SAAS,aAAa,EAC/B,MAAM,EAAE,CAAC,KACN,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;KAClC,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+EG;IACH,MAAM,CAAC,MAAM,WAAW,GACtB,KAAK,CAAC,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,EAElE,SAAS,OAAO,KACf,iBAAiB,CAAC,OAAO,CAAC,SAAS,IAAI,GACtC,mBAAmB,CAAC,eAAe,CAAC,OAAO,CAAC,GAC5C,mBAAmB,CAAC,mBAAmB,CACrC,mBAAmB,CAAC,aAAa,CAAC,OAAO,CAAC,EAC1C,MAAM,CACJ,mBAAmB,CAAC,aAAa,CAAC,OAAO,CAAC,EAC1C,mBAAmB,CAAC,eAAe,CAAC,OAAO,CAAC,CAC7C,CACsC,CAAC;IAE9C;;;OAGG;IACH,UAAkB,mBAAmB,CAAC;QACpC,KAAK,cAAc,GAAG,EAAE,CAAC;QAEzB;;WAEG;QACH,KAAY,eAAe,CACzB,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,IAE1D,QAAQ,CAAC,mBAAmB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;QAE/C,gBAAgB;QAChB,KAAK,mBAAmB,CACtB,CAAC,EACD,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,IAE5D,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,IAAI,GACrC,CAAC,GACD,mBAAmB,CACjB,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAClD,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CACnB,CAAC;QAER;;;;;;;WAOG;QACH,KAAY,aAAa,CACvB,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,IAC1D,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAEtD,KAAK,iBAAiB,CACpB,CAAC,EACD,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,EAC5D,sBAAsB,SAAS,MAAM,IAErC,MAAM,CAAC,sBAAsB,EAAE,CAAC,CAAC,SAAS,IAAI,GAC1C,CAAC,GACD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,IAAI,GACvC,CAAC,GACD,iBAAiB,CACf,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACjB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAClB,SAAS,CAAC,sBAAsB,CAAC,CAClC,CAAC;QAEV,KAAY,eAAe,CACzB,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,IAC1D,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAExD,KAAK,mBAAmB,CACtB,CAAC,EACD,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,EAC5D,sBAAsB,SAAS,MAAM,IAErC,MAAM,CAAC,sBAAsB,EAAE,CAAC,CAAC,SAAS,IAAI,GAC1C,CAAC,GACD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,IAAI,GACvC,CAAC,GACD,mBAAmB,CACjB,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACjB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAClB,SAAS,CAAC,sBAAsB,CAAC,CAClC,CAAC;QAEV,KAAY,mBAAmB,CAAC,CAAC,EAAE,CAAC,IAClC,OAAO,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAC5C;;CACF"}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */
|
|
2
|
+
/**
|
|
3
|
+
* A collection of type-safe object utility functions providing functional programming patterns
|
|
4
|
+
* for object manipulation, including pick, omit, shallow equality checks, and more.
|
|
5
|
+
*
|
|
6
|
+
* All functions maintain TypeScript type safety and support both direct and curried usage patterns
|
|
7
|
+
* for better composition with pipe operations.
|
|
8
|
+
*/
|
|
9
|
+
var Obj;
|
|
10
|
+
(function (Obj) {
|
|
11
|
+
/**
|
|
12
|
+
* Performs a shallow equality check on two records using a configurable equality function.
|
|
13
|
+
* Verifies that both records have the same number of entries and that for every key in the first record,
|
|
14
|
+
* the corresponding value passes the equality test with the value in the second record.
|
|
15
|
+
*
|
|
16
|
+
* @param a - The first record to compare
|
|
17
|
+
* @param b - The second record to compare
|
|
18
|
+
* @param eq - Optional equality function (defaults to Object.is for strict equality)
|
|
19
|
+
* @returns `true` if the records are shallowly equal according to the equality function, `false` otherwise
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* // Basic usage with default Object.is equality
|
|
24
|
+
* Obj.shallowEq({ x: 1, y: 2 }, { x: 1, y: 2 }); // true
|
|
25
|
+
* Obj.shallowEq({ x: 1 }, { x: 1, y: 2 }); // false (different number of keys)
|
|
26
|
+
* Obj.shallowEq({ x: 1 }, { x: 2 }); // false (different values)
|
|
27
|
+
* Obj.shallowEq({}, {}); // true (both empty)
|
|
28
|
+
*
|
|
29
|
+
* // String comparisons
|
|
30
|
+
* Obj.shallowEq({ a: "hello" }, { a: "hello" }); // true
|
|
31
|
+
* Obj.shallowEq({ a: "hello" }, { a: "world" }); // false
|
|
32
|
+
*
|
|
33
|
+
* // Using custom equality function
|
|
34
|
+
* const caseInsensitiveEq = (a: unknown, b: unknown) =>
|
|
35
|
+
* typeof a === 'string' && typeof b === 'string'
|
|
36
|
+
* ? a.toLowerCase() === b.toLowerCase()
|
|
37
|
+
* : a === b;
|
|
38
|
+
*
|
|
39
|
+
* Obj.shallowEq({ name: "ALICE" }, { name: "alice" }, caseInsensitiveEq); // true
|
|
40
|
+
*
|
|
41
|
+
* // Handling special values
|
|
42
|
+
* Obj.shallowEq({ x: NaN }, { x: NaN }); // true (Object.is treats NaN === NaN)
|
|
43
|
+
* Obj.shallowEq({ x: +0 }, { x: -0 }); // false (Object.is distinguishes +0 and -0)
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
Obj.shallowEq = (a, b, eq = Object.is) => {
|
|
47
|
+
const aEntries = Object.entries(a);
|
|
48
|
+
const bEntries = Object.entries(b);
|
|
49
|
+
if (aEntries.length !== bEntries.length)
|
|
50
|
+
return false;
|
|
51
|
+
return aEntries.every(([k, v]) => eq(b[k], v));
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Creates a new record that contains only the specified keys from the source record.
|
|
55
|
+
* This function supports both direct usage and curried form for functional composition.
|
|
56
|
+
*
|
|
57
|
+
* **Type Safety**: Only keys that exist in the source record type are allowed,
|
|
58
|
+
* preventing runtime errors from accessing non-existent properties.
|
|
59
|
+
*
|
|
60
|
+
* @template R - The type of the input record
|
|
61
|
+
* @template Keys - The readonly array type of keys to pick from the record
|
|
62
|
+
*
|
|
63
|
+
* @param record - The source record to pick properties from
|
|
64
|
+
* @param keys - A readonly array of keys to include in the result
|
|
65
|
+
* @returns A new record containing only the specified keys and their values
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* // Direct usage
|
|
70
|
+
* const original = { a: 1, b: 2, c: 3, d: 4 };
|
|
71
|
+
* Obj.pick(original, ['a', 'c']); // { a: 1, c: 3 }
|
|
72
|
+
* Obj.pick(original, ['b']); // { b: 2 }
|
|
73
|
+
* Obj.pick(original, []); // {} (empty result)
|
|
74
|
+
*
|
|
75
|
+
* // Real-world example with user data
|
|
76
|
+
* const user = {
|
|
77
|
+
* id: 1,
|
|
78
|
+
* name: "Alice",
|
|
79
|
+
* email: "alice@example.com",
|
|
80
|
+
* password: "secret123",
|
|
81
|
+
* age: 30
|
|
82
|
+
* };
|
|
83
|
+
*
|
|
84
|
+
* // Extract public user information
|
|
85
|
+
* const publicUser = Obj.pick(user, ['id', 'name', 'email']);
|
|
86
|
+
* // Result: { id: 1, name: "Alice", email: "alice@example.com" }
|
|
87
|
+
*
|
|
88
|
+
* // Curried usage for functional composition
|
|
89
|
+
* const pickIdAndName = Obj.pick(['id', 'name'] as const);
|
|
90
|
+
* const users = [user, { id: 2, name: "Bob", email: "bob@example.com", age: 25 }];
|
|
91
|
+
* const publicUsers = users.map(pickIdAndName);
|
|
92
|
+
* // Result: [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]
|
|
93
|
+
*
|
|
94
|
+
* // Using with pipe for data transformation
|
|
95
|
+
* import { pipe } from '../functional/pipe.mjs';
|
|
96
|
+
* const result = pipe(user)
|
|
97
|
+
* .map(Obj.pick(['id', 'name']))
|
|
98
|
+
* .map(u => ({ ...u, displayName: u.name.toUpperCase() }))
|
|
99
|
+
* .value;
|
|
100
|
+
* // Result: { id: 1, name: "Alice", displayName: "ALICE" }
|
|
101
|
+
*
|
|
102
|
+
* // Type safety prevents invalid keys
|
|
103
|
+
* // Obj.pick(user, ['invalidKey']); // ❌ TypeScript error
|
|
104
|
+
* // Obj.pick(user, ['id', 'nonExistentField']); // ❌ TypeScript error
|
|
105
|
+
*
|
|
106
|
+
* // Partial key selection (when some keys might not exist)
|
|
107
|
+
* const partialUser = { id: 1, name: "Alice" } as const;
|
|
108
|
+
* const pickVisible = Obj.pick(['name', 'age']); // age might not exist
|
|
109
|
+
* const visible = pickVisible(partialUser); // { name: "Alice" } (age omitted)
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
Obj.pick = ((...args) => {
|
|
113
|
+
switch (args.length) {
|
|
114
|
+
case 2: {
|
|
115
|
+
const [record, keys] = args;
|
|
116
|
+
const keysSet = new Set(keys);
|
|
117
|
+
return Object.fromEntries(Object.entries(record).filter(([k, _v]) => keysSet.has(k)));
|
|
118
|
+
}
|
|
119
|
+
case 1: {
|
|
120
|
+
const [keys] = args;
|
|
121
|
+
return (record) => Obj.pick(record, keys);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
/**
|
|
126
|
+
* Creates a new record that excludes the specified keys from the source record.
|
|
127
|
+
* This function supports both direct usage and curried form for functional composition.
|
|
128
|
+
*
|
|
129
|
+
* **Type Safety**: Only keys that exist in the source record type are allowed,
|
|
130
|
+
* and the return type precisely reflects which properties remain after omission.
|
|
131
|
+
*
|
|
132
|
+
* @template R - The type of the input record
|
|
133
|
+
* @template Keys - The readonly array type of keys to omit from the record
|
|
134
|
+
*
|
|
135
|
+
* @param record - The source record to omit properties from
|
|
136
|
+
* @param keys - A readonly array of keys to exclude from the result
|
|
137
|
+
* @returns A new record containing all properties except the specified keys
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* // Direct usage
|
|
142
|
+
* const original = { a: 1, b: 2, c: 3, d: 4 };
|
|
143
|
+
* Obj.omit(original, ['a', 'c']); // { b: 2, d: 4 }
|
|
144
|
+
* Obj.omit(original, ['b']); // { a: 1, c: 3, d: 4 }
|
|
145
|
+
* Obj.omit(original, []); // { a: 1, b: 2, c: 3, d: 4 } (no keys omitted)
|
|
146
|
+
*
|
|
147
|
+
* // Real-world example: removing sensitive data
|
|
148
|
+
* const user = {
|
|
149
|
+
* id: 1,
|
|
150
|
+
* name: "Alice",
|
|
151
|
+
* email: "alice@example.com",
|
|
152
|
+
* password: "secret123",
|
|
153
|
+
* apiKey: "abc-def-ghi",
|
|
154
|
+
* lastLogin: new Date()
|
|
155
|
+
* };
|
|
156
|
+
*
|
|
157
|
+
* // Create safe user object for client-side
|
|
158
|
+
* const safeUser = Obj.omit(user, ['password', 'apiKey']);
|
|
159
|
+
* // Result: { id: 1, name: "Alice", email: "alice@example.com", lastLogin: Date }
|
|
160
|
+
*
|
|
161
|
+
* // Curried usage for data processing pipelines
|
|
162
|
+
* const removeSensitive = Obj.omit(['password', 'apiKey', 'ssn'] as const);
|
|
163
|
+
* const users = [user]; // array of user objects
|
|
164
|
+
* const safeUsers = users.map(removeSensitive);
|
|
165
|
+
*
|
|
166
|
+
* // Using with pipe for complex transformations
|
|
167
|
+
* import { pipe } from '../functional/pipe.mjs';
|
|
168
|
+
* const publicProfile = pipe(user)
|
|
169
|
+
* .map(Obj.omit(['password', 'apiKey']))
|
|
170
|
+
* .map(u => ({ ...u, displayName: u.name.toUpperCase() }))
|
|
171
|
+
* .value;
|
|
172
|
+
* // Result: { id: 1, name: "Alice", email: "...", lastLogin: Date, displayName: "ALICE" }
|
|
173
|
+
*
|
|
174
|
+
* // Database queries: exclude computed fields
|
|
175
|
+
* const dbUser = {
|
|
176
|
+
* id: 1,
|
|
177
|
+
* name: "Alice",
|
|
178
|
+
* email: "alice@example.com",
|
|
179
|
+
* createdAt: new Date(),
|
|
180
|
+
* updatedAt: new Date(),
|
|
181
|
+
* fullName: "Alice Johnson", // computed field
|
|
182
|
+
* isActive: true // computed field
|
|
183
|
+
* };
|
|
184
|
+
*
|
|
185
|
+
* const storableData = Obj.omit(dbUser, ['fullName', 'isActive']);
|
|
186
|
+
* // Only data that should be persisted to database
|
|
187
|
+
*
|
|
188
|
+
* // Type safety prevents invalid operations
|
|
189
|
+
* // Obj.omit(user, ['invalidKey']); // ❌ TypeScript error
|
|
190
|
+
* // Obj.omit(user, ['id', 'nonExistentField']); // ❌ TypeScript error
|
|
191
|
+
*
|
|
192
|
+
* // Handling partial omission (when some keys might not exist)
|
|
193
|
+
* const partialUser = { id: 1, name: "Alice", password: "secret" } as const;
|
|
194
|
+
* const omitCredentials = Obj.omit(['password', 'apiKey']); // apiKey might not exist
|
|
195
|
+
* const cleaned = omitCredentials(partialUser); // { id: 1, name: "Alice" }
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
Obj.omit = ((...args) => {
|
|
199
|
+
switch (args.length) {
|
|
200
|
+
case 2: {
|
|
201
|
+
const [record, keys] = args;
|
|
202
|
+
const keysSet = new Set(keys);
|
|
203
|
+
return Object.fromEntries(Object.entries(record).filter(([k, _v]) => !keysSet.has(k)));
|
|
204
|
+
}
|
|
205
|
+
case 1: {
|
|
206
|
+
const [keys] = args;
|
|
207
|
+
return (record) => Obj.omit(record, keys);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
/**
|
|
212
|
+
* Creates an object from an array of key-value pairs with precise TypeScript typing.
|
|
213
|
+
* This is a type-safe wrapper around `Object.fromEntries` that provides better type inference
|
|
214
|
+
* and compile-time guarantees about the resulting object structure.
|
|
215
|
+
*
|
|
216
|
+
* **Type Behavior**:
|
|
217
|
+
* - When entries is a fixed-length tuple, the exact object type is inferred
|
|
218
|
+
* - When entries has dynamic length with union key types, `Partial` is applied to prevent
|
|
219
|
+
* incorrect assumptions about which keys will be present
|
|
220
|
+
*
|
|
221
|
+
* @template Entries - The readonly array type of key-value entry tuples
|
|
222
|
+
* @param entries - An array of readonly key-value entry tuples `[key, value]`
|
|
223
|
+
* @returns An object created from the entries with precise typing
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```typescript
|
|
227
|
+
* // Fixed entries with precise typing
|
|
228
|
+
* const fixedEntries = [
|
|
229
|
+
* ['name', 'Alice'],
|
|
230
|
+
* ['age', 30],
|
|
231
|
+
* ['active', true]
|
|
232
|
+
* ] as const;
|
|
233
|
+
*
|
|
234
|
+
* const user = Obj.fromEntries(fixedEntries);
|
|
235
|
+
* // Type: { readonly name: "Alice"; readonly age: 30; readonly active: true }
|
|
236
|
+
* // Value: { name: "Alice", age: 30, active: true }
|
|
237
|
+
*
|
|
238
|
+
* // Simple coordinate example
|
|
239
|
+
* const coordEntries = [['x', 1], ['y', 3]] as const;
|
|
240
|
+
* const point = Obj.fromEntries(coordEntries);
|
|
241
|
+
* // Type: { readonly x: 1; readonly y: 3 }
|
|
242
|
+
* // Value: { x: 1, y: 3 }
|
|
243
|
+
*
|
|
244
|
+
* // Dynamic entries with union keys
|
|
245
|
+
* const dynamicEntries: Array<['name' | 'email', string]> = [
|
|
246
|
+
* ['name', 'Alice']
|
|
247
|
+
* // email might or might not be present
|
|
248
|
+
* ];
|
|
249
|
+
* const partialUser = Obj.fromEntries(dynamicEntries);
|
|
250
|
+
* // Type: Partial<{ name: string; email: string }>
|
|
251
|
+
* // This prevents assuming both 'name' and 'email' are always present
|
|
252
|
+
*
|
|
253
|
+
* // Creating configuration objects
|
|
254
|
+
* const configEntries = [
|
|
255
|
+
* ['apiUrl', 'https://api.example.com'],
|
|
256
|
+
* ['timeout', 5000],
|
|
257
|
+
* ['retries', 3],
|
|
258
|
+
* ['debug', false]
|
|
259
|
+
* ] as const;
|
|
260
|
+
* const config = Obj.fromEntries(configEntries);
|
|
261
|
+
* // Precise types for each configuration value
|
|
262
|
+
*
|
|
263
|
+
* // Converting Maps to objects
|
|
264
|
+
* const settingsMap = new Map([
|
|
265
|
+
* ['theme', 'dark'],
|
|
266
|
+
* ['language', 'en'],
|
|
267
|
+
* ['notifications', true]
|
|
268
|
+
* ] as const);
|
|
269
|
+
* const settings = Obj.fromEntries([...settingsMap]);
|
|
270
|
+
*
|
|
271
|
+
* // Building objects from computed entries
|
|
272
|
+
* const keys = ['a', 'b', 'c'] as const;
|
|
273
|
+
* const values = [1, 2, 3] as const;
|
|
274
|
+
* const computedEntries = keys.map((k, i) => [k, values[i]] as const);
|
|
275
|
+
* const computed = Obj.fromEntries(computedEntries);
|
|
276
|
+
* // Type reflects the specific key-value associations
|
|
277
|
+
*
|
|
278
|
+
* // Error handling with validation
|
|
279
|
+
* function createUserFromEntries(entries: ReadonlyArray<readonly [string, unknown]>) {
|
|
280
|
+
* const user = Obj.fromEntries(entries);
|
|
281
|
+
* // Type is Partial<Record<string, unknown>> - safe for dynamic data
|
|
282
|
+
*
|
|
283
|
+
* if ('name' in user && typeof user.name === 'string') {
|
|
284
|
+
* // Type narrowing works correctly
|
|
285
|
+
* return { name: user.name, ...user };
|
|
286
|
+
* }
|
|
287
|
+
* throw new Error('Invalid user data');
|
|
288
|
+
* }
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
291
|
+
Obj.fromEntries = (entries) => Object.fromEntries(entries);
|
|
292
|
+
})(Obj || (Obj = {}));
|
|
293
|
+
|
|
294
|
+
export { Obj };
|
|
295
|
+
//# sourceMappingURL=object.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object.mjs","sources":["../../src/object/object.mts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;AACA;;;;;;AAMG;AACG,IAAW;AAAjB,CAAA,UAAiB,GAAG,EAAA;AAClB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;IACU,GAAA,CAAA,SAAS,GAAG,CACvB,CAAgB,EAChB,CAAgB,EAChB,EAAA,GAA0C,MAAM,CAAC,EAAE,KACxC;QACX,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAElC,QAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;AAAE,YAAA,OAAO,KAAK;QAErD,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAChD,KAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DG;AACU,IAAA,GAAA,CAAA,IAAI,IAAoB,CAInC,GAAG,IAEwC,KAGa;AACxD,QAAA,QAAQ,IAAI,CAAC,MAAM;YACjB,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI;AAC3B,gBAAA,MAAM,OAAO,GAAG,IAAI,GAAG,CAAU,IAAI,CAAC;AAEtC,gBAAA,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAClD;;YAGZ,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI;AACnB,gBAAA,OAAO,CAA2B,MAAU,KAC1C,GAAA,CAAA,IAAI,CAAC,MAAM,EAAE,IAA6B,CAAC;;;AAGnD,KAAC,CAAmB;AAgBpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwEG;AACU,IAAA,GAAA,CAAA,IAAI,IAAoB,CAInC,GAAG,IAEwC,KAGM;AACjD,QAAA,QAAQ,IAAI,CAAC,MAAM;YACjB,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI;AAC3B,gBAAA,MAAM,OAAO,GAAG,IAAI,GAAG,CAAU,IAAI,CAAC;AAEtC,gBAAA,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CACnD;;YAGZ,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI;AACnB,gBAAA,OAAO,CAA2B,MAAU,KAC1C,GAAA,CAAA,IAAI,CAAC,MAAM,EAAE,IAA6B,CAGzC;;;AAGT,KAAC,CAAmB;AAgBpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+EG;AACU,IAAA,GAAA,CAAA,WAAW,GAAG,CAGzB,OAAgB,KAST,MAAM,CAAC,WAAW,CAAC,OAAO,CAAU;AA8E/C,CAAC,EAtbgB,GAAG,KAAH,GAAG,GAAA,EAAA,CAAA,CAAA;;;;"}
|