ts-data-forge 6.4.0 → 6.6.0

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.
Files changed (181) hide show
  1. package/README.md +5 -3
  2. package/dist/array/impl/array-utils-element-access.d.mts +5 -5
  3. package/dist/array/impl/array-utils-element-access.mjs +4 -4
  4. package/dist/array/impl/array-utils-iterators.d.mts +1 -1
  5. package/dist/array/impl/array-utils-iterators.mjs +1 -1
  6. package/dist/array/impl/array-utils-modification.d.mts +4 -4
  7. package/dist/array/impl/array-utils-reducing-value.d.mts +5 -5
  8. package/dist/array/impl/array-utils-reducing-value.d.mts.map +1 -1
  9. package/dist/array/impl/array-utils-reducing-value.mjs +1 -0
  10. package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
  11. package/dist/array/impl/array-utils-search.d.mts +8 -8
  12. package/dist/array/impl/array-utils-set-op.d.mts.map +1 -1
  13. package/dist/array/impl/array-utils-set-op.mjs +3 -1
  14. package/dist/array/impl/array-utils-set-op.mjs.map +1 -1
  15. package/dist/array/impl/array-utils-size.d.mts +1 -1
  16. package/dist/array/impl/array-utils-size.mjs +1 -1
  17. package/dist/array/impl/array-utils-slice-clamped.d.mts +1 -1
  18. package/dist/array/impl/array-utils-slicing.d.mts +3 -3
  19. package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
  20. package/dist/array/impl/array-utils-validation.d.mts +7 -7
  21. package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
  22. package/dist/array/impl/array-utils-validation.mjs +22 -12
  23. package/dist/array/impl/array-utils-validation.mjs.map +1 -1
  24. package/dist/collections/imap-mapped.d.mts +5 -12
  25. package/dist/collections/imap-mapped.d.mts.map +1 -1
  26. package/dist/collections/imap-mapped.mjs.map +1 -1
  27. package/dist/collections/imap.d.mts +24 -28
  28. package/dist/collections/imap.d.mts.map +1 -1
  29. package/dist/collections/imap.mjs +1 -1
  30. package/dist/collections/imap.mjs.map +1 -1
  31. package/dist/collections/iset-mapped.d.mts +8 -14
  32. package/dist/collections/iset-mapped.d.mts.map +1 -1
  33. package/dist/collections/iset-mapped.mjs.map +1 -1
  34. package/dist/collections/iset.d.mts +9 -23
  35. package/dist/collections/iset.d.mts.map +1 -1
  36. package/dist/collections/iset.mjs +1 -0
  37. package/dist/collections/iset.mjs.map +1 -1
  38. package/dist/entry-point.mjs +1 -0
  39. package/dist/entry-point.mjs.map +1 -1
  40. package/dist/functional/optional/impl/optional-is-optional.d.mts +1 -1
  41. package/dist/functional/optional/impl/optional-is-optional.d.mts.map +1 -1
  42. package/dist/functional/optional/impl/optional-is-optional.mjs +6 -5
  43. package/dist/functional/optional/impl/optional-is-optional.mjs.map +1 -1
  44. package/dist/functional/optional/impl/optional-some.d.mts.map +1 -1
  45. package/dist/functional/optional/impl/optional-some.mjs.map +1 -1
  46. package/dist/functional/optional/impl/optional-zip.d.mts +1 -1
  47. package/dist/functional/optional/impl/optional-zip.mjs +1 -1
  48. package/dist/functional/result/impl/result-err.d.mts.map +1 -1
  49. package/dist/functional/result/impl/result-err.mjs.map +1 -1
  50. package/dist/functional/result/impl/result-is-result.d.mts +1 -1
  51. package/dist/functional/result/impl/result-is-result.mjs +1 -1
  52. package/dist/functional/result/impl/result-ok.d.mts.map +1 -1
  53. package/dist/functional/result/impl/result-ok.mjs.map +1 -1
  54. package/dist/functional/result/impl/result-unwrap-err-throw.mjs +1 -0
  55. package/dist/functional/result/impl/result-unwrap-err-throw.mjs.map +1 -1
  56. package/dist/functional/result/impl/result-unwrap-throw.mjs +1 -0
  57. package/dist/functional/result/impl/result-unwrap-throw.mjs.map +1 -1
  58. package/dist/functional/ternary-result/impl/ternary-result-err.d.mts.map +1 -1
  59. package/dist/functional/ternary-result/impl/ternary-result-err.mjs.map +1 -1
  60. package/dist/functional/ternary-result/impl/ternary-result-is-ternary-result.d.mts +1 -1
  61. package/dist/functional/ternary-result/impl/ternary-result-is-ternary-result.mjs +1 -1
  62. package/dist/functional/ternary-result/impl/ternary-result-ok.d.mts.map +1 -1
  63. package/dist/functional/ternary-result/impl/ternary-result-ok.mjs.map +1 -1
  64. package/dist/functional/ternary-result/impl/ternary-result-unwrap-err-throw.mjs +1 -0
  65. package/dist/functional/ternary-result/impl/ternary-result-unwrap-err-throw.mjs.map +1 -1
  66. package/dist/functional/ternary-result/impl/ternary-result-unwrap-throw.mjs +1 -0
  67. package/dist/functional/ternary-result/impl/ternary-result-unwrap-throw.mjs.map +1 -1
  68. package/dist/functional/ternary-result/impl/ternary-result-unwrap-warn-throw.mjs +1 -0
  69. package/dist/functional/ternary-result/impl/ternary-result-unwrap-warn-throw.mjs.map +1 -1
  70. package/dist/functional/ternary-result/impl/ternary-result-warn.d.mts.map +1 -1
  71. package/dist/functional/ternary-result/impl/ternary-result-warn.mjs.map +1 -1
  72. package/dist/guard/has-key.d.mts +3 -1
  73. package/dist/guard/has-key.d.mts.map +1 -1
  74. package/dist/guard/has-key.mjs +6 -2
  75. package/dist/guard/has-key.mjs.map +1 -1
  76. package/dist/guard/is-non-null-object.d.mts.map +1 -1
  77. package/dist/guard/is-non-null-object.mjs +3 -1
  78. package/dist/guard/is-non-null-object.mjs.map +1 -1
  79. package/dist/guard/is-record.d.mts +2 -2
  80. package/dist/guard/is-record.mjs +2 -2
  81. package/dist/guard/is-type.d.mts +15 -15
  82. package/dist/guard/is-type.mjs +15 -15
  83. package/dist/guard/key-is-in.d.mts.map +1 -1
  84. package/dist/guard/key-is-in.mjs +3 -1
  85. package/dist/guard/key-is-in.mjs.map +1 -1
  86. package/dist/index.mjs +1 -0
  87. package/dist/index.mjs.map +1 -1
  88. package/dist/json/json.d.mts +3 -3
  89. package/dist/json/json.mjs +4 -3
  90. package/dist/json/json.mjs.map +1 -1
  91. package/dist/number/branded-types/non-zero-safe-int.mjs +2 -2
  92. package/dist/number/branded-types/positive-safe-int.mjs +1 -1
  93. package/dist/number/branded-types/safe-int.mjs +2 -2
  94. package/dist/number/branded-types/safe-uint.mjs +1 -1
  95. package/dist/number/num.mjs +1 -1
  96. package/dist/object/object.d.mts +36 -8
  97. package/dist/object/object.d.mts.map +1 -1
  98. package/dist/object/object.mjs +28 -6
  99. package/dist/object/object.mjs.map +1 -1
  100. package/dist/others/fast-deep-equal.d.mts +8 -0
  101. package/dist/others/fast-deep-equal.d.mts.map +1 -0
  102. package/dist/others/fast-deep-equal.mjs +72 -0
  103. package/dist/others/fast-deep-equal.mjs.map +1 -0
  104. package/dist/others/index.d.mts +1 -0
  105. package/dist/others/index.d.mts.map +1 -1
  106. package/dist/others/index.mjs +1 -0
  107. package/dist/others/index.mjs.map +1 -1
  108. package/package.json +34 -29
  109. package/src/array/impl/array-utils-creation.test.mts +13 -10
  110. package/src/array/impl/array-utils-element-access.mts +5 -5
  111. package/src/array/impl/array-utils-element-access.test.mts +5 -5
  112. package/src/array/impl/array-utils-iterators.mts +1 -1
  113. package/src/array/impl/array-utils-iterators.test.mts +6 -6
  114. package/src/array/impl/array-utils-modification.mts +4 -4
  115. package/src/array/impl/array-utils-modification.test.mts +12 -12
  116. package/src/array/impl/array-utils-overload-type-error.test.mts +1 -1
  117. package/src/array/impl/array-utils-reducing-value.mts +6 -5
  118. package/src/array/impl/array-utils-reducing-value.test.mts +9 -9
  119. package/src/array/impl/array-utils-search.mts +8 -8
  120. package/src/array/impl/array-utils-search.test.mts +35 -35
  121. package/src/array/impl/array-utils-set-op.mts +1 -0
  122. package/src/array/impl/array-utils-set-op.test.mts +2 -2
  123. package/src/array/impl/array-utils-size.mts +1 -1
  124. package/src/array/impl/array-utils-size.test.mts +1 -1
  125. package/src/array/impl/array-utils-slice-clamped.mts +1 -1
  126. package/src/array/impl/array-utils-slice-clamped.test.mts +5 -5
  127. package/src/array/impl/array-utils-slicing.mts +3 -3
  128. package/src/array/impl/array-utils-slicing.test.mts +5 -5
  129. package/src/array/impl/array-utils-transformation.mts +1 -1
  130. package/src/array/impl/array-utils-transformation.test.mts +53 -53
  131. package/src/array/impl/array-utils-validation.mts +18 -10
  132. package/src/array/impl/array-utils-validation.test.mts +34 -29
  133. package/src/array/impl/array.test.mts +1 -1
  134. package/src/collections/imap-mapped.mts +4 -10
  135. package/src/collections/imap-mapped.test.mts +9 -9
  136. package/src/collections/imap.mts +24 -27
  137. package/src/collections/imap.test.mts +6 -6
  138. package/src/collections/iset-mapped.mts +12 -16
  139. package/src/collections/iset-mapped.test.mts +6 -6
  140. package/src/collections/iset.mts +14 -25
  141. package/src/collections/queue.test.mts +2 -1
  142. package/src/collections/stack.test.mts +3 -3
  143. package/src/functional/optional/impl/optional-is-optional.mts +6 -6
  144. package/src/functional/optional/impl/optional-some.mts +5 -4
  145. package/src/functional/optional/impl/optional-zip.mts +1 -1
  146. package/src/functional/result/impl/result-err.mts +5 -4
  147. package/src/functional/result/impl/result-is-result.mts +1 -1
  148. package/src/functional/result/impl/result-ok.mts +5 -4
  149. package/src/functional/result.test.mts +2 -2
  150. package/src/functional/ternary-result/impl/ternary-result-err.mts +5 -4
  151. package/src/functional/ternary-result/impl/ternary-result-is-ternary-result.mts +1 -1
  152. package/src/functional/ternary-result/impl/ternary-result-ok.mts +5 -4
  153. package/src/functional/ternary-result/impl/ternary-result-warn.mts +6 -5
  154. package/src/guard/has-key.mts +6 -2
  155. package/src/guard/is-error.test.mts +1 -1
  156. package/src/guard/is-non-empty-string.test.mts +1 -1
  157. package/src/guard/is-non-null-object.mts +1 -0
  158. package/src/guard/is-non-null-object.test.mts +4 -3
  159. package/src/guard/is-primitive.test.mts +1 -1
  160. package/src/guard/is-record.mts +2 -2
  161. package/src/guard/is-record.test.mts +2 -2
  162. package/src/guard/is-type.mts +15 -15
  163. package/src/guard/is-type.test.mts +2 -2
  164. package/src/guard/key-is-in.mts +3 -1
  165. package/src/json/json.mts +4 -3
  166. package/src/json/json.test.mts +20 -19
  167. package/src/number/branded-types/non-zero-safe-int.mts +2 -2
  168. package/src/number/branded-types/positive-safe-int.mts +1 -1
  169. package/src/number/branded-types/safe-int.mts +2 -2
  170. package/src/number/branded-types/safe-uint.mts +1 -1
  171. package/src/number/num.mts +1 -1
  172. package/src/object/object.mts +54 -8
  173. package/src/object/object.test.mts +70 -7
  174. package/src/others/cast-mutable.test.mts +3 -3
  175. package/src/others/cast-readonly.test.mts +10 -5
  176. package/src/others/fast-deep-equal.mts +98 -0
  177. package/src/others/fast-deep-equal.test.mts +771 -0
  178. package/src/others/index.mts +1 -0
  179. package/src/others/map-nullable.test.mts +8 -8
  180. package/src/others/memoize-function.test.mts +20 -8
  181. package/src/others/unknown-to-string.test.mts +8 -8
@@ -2,13 +2,13 @@ import { ISetMapped } from './iset-mapped.mjs';
2
2
 
3
3
  const toKey = (a: Readonly<{ v: number }>): number => a.v;
4
4
 
5
- const fromKey = (k: number): Readonly<{ v: number }> => ({ v: k });
5
+ const fromKey = (k: number): Readonly<{ v: number }> => ({ v: k }) as const;
6
6
 
7
7
  // Test types for additional functionality
8
8
  type TestElement = Readonly<{ id: number; type: string }>;
9
9
 
10
10
  const testElementToString = (el: Readonly<TestElement>): string =>
11
- `${el.type}_${el.id}`;
11
+ `${el.type}_${el.id}` as const;
12
12
 
13
13
  const stringToTestElement = (str: string): TestElement => {
14
14
  const [type, idStr] = str.split('_');
@@ -185,7 +185,7 @@ describe('ISetMapped.forEach', () => {
185
185
  fromKey,
186
186
  );
187
187
 
188
- const elements = [{ v: 1 }, { v: 2 }, { v: 3 }];
188
+ const elements = [{ v: 1 }, { v: 2 }, { v: 3 }] as const;
189
189
 
190
190
  for (const el of s0) {
191
191
  expect(elements).toContainEqual(el);
@@ -201,7 +201,7 @@ describe('ISetMapped.keys', () => {
201
201
  fromKey,
202
202
  );
203
203
 
204
- const elements = [{ v: 1 }, { v: 2 }, { v: 3 }];
204
+ const elements = [{ v: 1 }, { v: 2 }, { v: 3 }] as const;
205
205
 
206
206
  for (const k of s0.keys()) {
207
207
  expect(elements).toContainEqual(k);
@@ -217,7 +217,7 @@ describe('ISetMapped.values', () => {
217
217
  fromKey,
218
218
  );
219
219
 
220
- const elements = [{ v: 1 }, { v: 2 }, { v: 3 }];
220
+ const elements = [{ v: 1 }, { v: 2 }, { v: 3 }] as const;
221
221
 
222
222
  for (const v of s0.values()) {
223
223
  expect(elements).toContainEqual(v);
@@ -233,7 +233,7 @@ describe('ISetMapped.entries', () => {
233
233
  fromKey,
234
234
  );
235
235
 
236
- const elements = [{ v: 1 }, { v: 2 }, { v: 3 }];
236
+ const elements = [{ v: 1 }, { v: 2 }, { v: 3 }] as const;
237
237
 
238
238
  for (const [k, v] of s0.entries()) {
239
239
  expect(elements).toContainEqual(k);
@@ -83,7 +83,9 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
83
83
  // Reducing a value
84
84
 
85
85
  /**
86
- * Checks if all elements in the set satisfy a predicate.
86
+ * Checks if all elements in the set satisfy a predicate. Also supports a
87
+ * type predicate overload that narrows the type of elements in the set if
88
+ * the predicate returns true for all elements.
87
89
  *
88
90
  * @example
89
91
  *
@@ -101,19 +103,11 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
101
103
  * assert.isTrue(narrowed);
102
104
  * ```
103
105
  *
106
+ * @template L The narrowed type of the elements.
104
107
  * @param predicate A function to test each element.
105
108
  * @returns `true` if all elements satisfy the predicate, `false` otherwise.
106
109
  */
107
110
  every: ((predicate: (key: K) => boolean) => boolean) &
108
- /**
109
- * Checks if all elements in the set satisfy a type predicate. Narrows the
110
- * type of elements in the set if the predicate returns true for all
111
- * elements.
112
- *
113
- * @template L The narrowed type of the elements.
114
- * @param predicate A type predicate function.
115
- * @returns `true` if all elements satisfy the predicate, `false` otherwise.
116
- */
117
111
  (<L extends K>(predicate: (key: K) => key is L) => this is ISet<L>);
118
112
 
119
113
  /**
@@ -194,7 +188,7 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
194
188
  * >[] = [
195
189
  * { type: 'add', key: 'c' },
196
190
  * { type: 'delete', key: 'a' },
197
- * ];
191
+ * ] as const;
198
192
  *
199
193
  * const mutated = base.withMutations(actions);
200
194
  *
@@ -234,8 +228,8 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
234
228
  map: <K2 extends MapSetKeyType>(mapFn: (key: K) => K2) => ISet<K2>;
235
229
 
236
230
  /**
237
- * Filters the elements of the set based on a type predicate. Narrows the type
238
- * of elements in the resulting set.
231
+ * Filters the elements of the set based on a predicate. Also supports a type
232
+ * predicate overload that narrows the type of elements in the resulting set.
239
233
  *
240
234
  * @example
241
235
  *
@@ -254,16 +248,10 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
254
248
  * ```
255
249
  *
256
250
  * @template K2 The narrowed type of the elements.
257
- * @param predicate A type predicate function.
258
- * @returns A new ISet instance with elements that satisfy the type predicate.
251
+ * @param predicate A function to test each element.
252
+ * @returns A new ISet instance with elements that satisfy the predicate.
259
253
  */
260
254
  filter: (<K2 extends K>(predicate: (key: K) => key is K2) => ISet<K2>) &
261
- /**
262
- * Filters the elements of the set based on a predicate.
263
- *
264
- * @param predicate A function to test each element.
265
- * @returns A new ISet instance with elements that satisfy the predicate.
266
- */
267
255
  ((predicate: (key: K) => boolean) => ISet<K>);
268
256
 
269
257
  /**
@@ -637,10 +625,11 @@ export namespace ISet {
637
625
  export const diff = <K extends MapSetKeyType>(
638
626
  oldSet: ISet<K>,
639
627
  newSet: ISet<K>,
640
- ): ReadonlyRecord<'added' | 'deleted', ISet<K>> => ({
641
- deleted: oldSet.subtract(newSet),
642
- added: newSet.subtract(oldSet),
643
- });
628
+ ): ReadonlyRecord<'added' | 'deleted', ISet<K>> =>
629
+ ({
630
+ deleted: oldSet.subtract(newSet),
631
+ added: newSet.subtract(oldSet),
632
+ }) as const;
644
633
 
645
634
  /**
646
635
  * Computes the intersection of two ISet instances.
@@ -585,7 +585,8 @@ describe('Queue test', () => {
585
585
  // Perform 1000 random operations
586
586
  for (const _i of range(asUint32(1000))) {
587
587
  // Randomly decide to enqueue or dequeue
588
- const shouldEnqueue = mut_expected.length === 0 || Math.random() < 0.6;
588
+ const shouldEnqueue =
589
+ Arr.isArrayOfLength(mut_expected, 0) || Math.random() < 0.6;
589
590
 
590
591
  if (shouldEnqueue) {
591
592
  mut_counter += 1;
@@ -153,9 +153,9 @@ describe('Stack test', () => {
153
153
 
154
154
  const stack = createStack<Item>();
155
155
 
156
- const item1: Item = { id: 1, name: 'first' };
156
+ const item1: Item = { id: 1, name: 'first' } as const;
157
157
 
158
- const item2: Item = { id: 2, name: 'second' };
158
+ const item2: Item = { id: 2, name: 'second' } as const;
159
159
 
160
160
  stack.push(item1);
161
161
 
@@ -198,7 +198,7 @@ describe('Stack test', () => {
198
198
  });
199
199
 
200
200
  test('should not mutate initial values array', () => {
201
- const initialValues = [1, 2, 3];
201
+ const initialValues = [1, 2, 3] as readonly number[];
202
202
 
203
203
  const originalLength = initialValues.length;
204
204
 
@@ -1,4 +1,4 @@
1
- import { isRecord } from '../../../guard/index.mjs';
1
+ import { hasKey, isRecord } from '../../../guard/index.mjs';
2
2
  import { NoneTypeTagName, SomeTypeTagName } from './tag.mjs';
3
3
 
4
4
  /**
@@ -9,7 +9,7 @@ import { NoneTypeTagName, SomeTypeTagName } from './tag.mjs';
9
9
  * ```ts
10
10
  * const maybeOptional = Optional.some('value');
11
11
  *
12
- * const notOptional = { $$tag: 'ts-data-forge::Optional.some' };
12
+ * const notOptional = { $$tag: 'ts-data-forge::Optional.some' } as const;
13
13
  *
14
14
  * assert.isTrue(Optional.isOptional(maybeOptional));
15
15
  *
@@ -23,7 +23,7 @@ export const isOptional = (
23
23
  maybeOptional: unknown,
24
24
  ): maybeOptional is Optional<unknown> =>
25
25
  isRecord(maybeOptional) &&
26
- Object.hasOwn(maybeOptional, '$$tag') &&
27
- ((maybeOptional['$$tag'] === SomeTypeTagName &&
28
- Object.hasOwn(maybeOptional, 'value')) ||
29
- maybeOptional['$$tag'] === NoneTypeTagName);
26
+ hasKey(maybeOptional, '$$tag') &&
27
+ ((maybeOptional.$$tag === SomeTypeTagName &&
28
+ hasKey(maybeOptional, 'value')) ||
29
+ maybeOptional.$$tag === NoneTypeTagName);
@@ -19,7 +19,8 @@ import { SomeTypeTagName } from './tag.mjs';
19
19
  * @param value The value to wrap in an {@link Some}.
20
20
  * @returns An {@link Some}<S> containing the value.
21
21
  */
22
- export const some = <const S,>(value: S): Some<S> => ({
23
- $$tag: SomeTypeTagName,
24
- value,
25
- });
22
+ export const some = <const S,>(value: S): Some<S> =>
23
+ ({
24
+ $$tag: SomeTypeTagName,
25
+ value,
26
+ }) as const;
@@ -14,7 +14,7 @@ import { some } from './optional-some.mjs';
14
14
  * assert.isTrue(Optional.isSome(zipped));
15
15
  *
16
16
  * if (Optional.isSome(zipped)) {
17
- * const expected: readonly [string, number] = ['left', 1];
17
+ * const expected: readonly [string, number] = ['left', 1] as const;
18
18
  *
19
19
  * assert.deepStrictEqual(zipped.value, expected);
20
20
  * }
@@ -25,7 +25,8 @@ import { ErrTypeTagName } from './tag.mjs';
25
25
  * @param value The error value.
26
26
  * @returns A `Result.Err<E>` containing the value.
27
27
  */
28
- export const err = <const E,>(value: E): Err<E> => ({
29
- $$tag: ErrTypeTagName,
30
- value,
31
- });
28
+ export const err = <const E,>(value: E): Err<E> =>
29
+ ({
30
+ $$tag: ErrTypeTagName,
31
+ value,
32
+ }) as const;
@@ -11,7 +11,7 @@ import { ErrTypeTagName, OkTypeTagName } from './tag.mjs';
11
11
  *
12
12
  * const errValue = Result.err(new Error('failure'));
13
13
  *
14
- * const notResult = { $$tag: 'ts-data-forge::Result.ok' };
14
+ * const notResult = { $$tag: 'ts-data-forge::Result.ok' } as const;
15
15
  *
16
16
  * assert.isTrue(Result.isResult(okValue));
17
17
  *
@@ -25,7 +25,8 @@ import { OkTypeTagName } from './tag.mjs';
25
25
  * @param value The success value.
26
26
  * @returns A `Result.Ok<S>` containing the value.
27
27
  */
28
- export const ok = <const S,>(value: S): Ok<S> => ({
29
- $$tag: OkTypeTagName,
30
- value,
31
- });
28
+ export const ok = <const S,>(value: S): Ok<S> =>
29
+ ({
30
+ $$tag: OkTypeTagName,
31
+ value,
32
+ }) as const;
@@ -821,7 +821,7 @@ describe('Result test', () => {
821
821
  });
822
822
 
823
823
  test('should return Ok with object when function succeeds', () => {
824
- const obj = { name: 'test', value: 123 };
824
+ const obj = { name: 'test', value: 123 } as const;
825
825
 
826
826
  const result = Result.fromThrowable(() => obj);
827
827
 
@@ -901,7 +901,7 @@ describe('Result test', () => {
901
901
  });
902
902
 
903
903
  test('should work with array access', () => {
904
- const arr = [1, 2, 3];
904
+ const arr = [1, 2, 3] as readonly number[];
905
905
 
906
906
  // This won't throw, but demonstrates the pattern
907
907
  const result = Result.fromThrowable(() => {
@@ -13,7 +13,8 @@ import { ErrTypeTagName } from './tag.mjs';
13
13
  * assert.isTrue(TernaryResult.isErr(failure));
14
14
  * ```
15
15
  */
16
- export const err = <const E,>(value: E): TernaryErr<E> => ({
17
- $$tag: ErrTypeTagName,
18
- value,
19
- });
16
+ export const err = <const E,>(value: E): TernaryErr<E> =>
17
+ ({
18
+ $$tag: ErrTypeTagName,
19
+ value,
20
+ }) as const;
@@ -11,7 +11,7 @@ import { ErrTypeTagName, OkTypeTagName, WarnTypeTagName } from './tag.mjs';
11
11
  *
12
12
  * const warnValue = TernaryResult.warn('done', 'retry later');
13
13
  *
14
- * const notResult = { $$tag: 'ts-data-forge::Result.ok' };
14
+ * const notResult = { $$tag: 'ts-data-forge::Result.ok' } as const;
15
15
  *
16
16
  * assert.isTrue(TernaryResult.isTernaryResult(okValue));
17
17
  *
@@ -14,7 +14,8 @@ import { OkTypeTagName } from './tag.mjs';
14
14
  * });
15
15
  * ```
16
16
  */
17
- export const ok = <const S,>(value: S): TernaryOk<S> => ({
18
- $$tag: OkTypeTagName,
19
- value,
20
- });
17
+ export const ok = <const S,>(value: S): TernaryOk<S> =>
18
+ ({
19
+ $$tag: OkTypeTagName,
20
+ value,
21
+ }) as const;
@@ -19,8 +19,9 @@ import { WarnTypeTagName } from './tag.mjs';
19
19
  export const warn = <const S, const W>(
20
20
  value: S,
21
21
  warning: W,
22
- ): TernaryWarn<S, W> => ({
23
- $$tag: WarnTypeTagName,
24
- value,
25
- warning,
26
- });
22
+ ): TernaryWarn<S, W> =>
23
+ ({
24
+ $$tag: WarnTypeTagName,
25
+ value,
26
+ warning,
27
+ }) as const;
@@ -17,7 +17,9 @@
17
17
  * @example
18
18
  *
19
19
  * ```ts
20
- * const maybeUser: Readonly<{ id?: number; name?: string }> = { id: 42 };
20
+ * const maybeUser: Readonly<{ id?: number; name?: string }> = {
21
+ * id: 42,
22
+ * } as const;
21
23
  *
22
24
  * if (hasKey(maybeUser, 'id')) {
23
25
  * // `maybeUser` is now known to have an `id` property.
@@ -43,7 +45,9 @@ export const hasKey = <
43
45
  >(
44
46
  obj: R,
45
47
  key: K,
46
- ): obj is HasKeyReturnType<R, K> => Object.hasOwn(obj, key);
48
+ ): obj is HasKeyReturnType<R, K> =>
49
+ // eslint-disable-next-line ts-data-forge/prefer-is-record-and-has-key
50
+ Object.hasOwn(obj, key);
47
51
 
48
52
  /**
49
53
  * @internal
@@ -84,7 +84,7 @@ describe('isError from @sindresorhus/is', () => {
84
84
  name: 'Error',
85
85
  message: 'This is not a real error',
86
86
  stack: 'fake stack trace',
87
- };
87
+ } as const;
88
88
 
89
89
  assert.isFalse(isErrorBySindreSorhus(errorLikeObject));
90
90
  });
@@ -84,7 +84,7 @@ describe(isNonEmptyString, () => {
84
84
  undefined,
85
85
  'third',
86
86
  false,
87
- ];
87
+ ] as const;
88
88
 
89
89
  // @ts-expect-error Testing non-string types
90
90
  const nonEmptyStrings = mixed.filter(isNonEmptyString);
@@ -33,4 +33,5 @@
33
33
  */
34
34
  // eslint-disable-next-line @typescript-eslint/no-restricted-types
35
35
  export const isNonNullObject = (u: unknown): u is object =>
36
+ // eslint-disable-next-line ts-data-forge/prefer-is-non-null-object
36
37
  typeof u === 'object' && u !== null;
@@ -73,7 +73,7 @@ describe(isNonNullObject, () => {
73
73
  });
74
74
 
75
75
  test('should act as a type guard', () => {
76
- const value: unknown = { test: true };
76
+ const value: unknown = { test: true } as const;
77
77
 
78
78
  if (isNonNullObject(value)) {
79
79
  expectType<typeof value, object>('=');
@@ -81,7 +81,8 @@ describe(isNonNullObject, () => {
81
81
  });
82
82
 
83
83
  test('should narrow nullable object types', () => {
84
- const nullable: UnknownRecord | null = Math.random() > 0.5 ? {} : null;
84
+ const nullable: UnknownRecord | null =
85
+ Math.random() > 0.5 ? ({} as const) : null;
85
86
 
86
87
  if (isNonNullObject(nullable)) {
87
88
  expectType<typeof nullable, UnknownRecord>('=');
@@ -98,7 +99,7 @@ describe(isNonNullObject, () => {
98
99
  [],
99
100
  () => {},
100
101
  true,
101
- ];
102
+ ] as const;
102
103
 
103
104
  const objects = mixed.filter(isNonNullObject);
104
105
 
@@ -102,7 +102,7 @@ describe(isPrimitive, () => {
102
102
  null,
103
103
  undefined,
104
104
  Symbol('test'),
105
- ];
105
+ ] as const;
106
106
 
107
107
  const primitives = values.filter(isPrimitive);
108
108
 
@@ -25,7 +25,7 @@ import { isNonNullObject } from './is-non-null-object.mjs';
25
25
  * @example
26
26
  *
27
27
  * ```ts
28
- * const entries: readonly unknown[] = [{ id: 1 }, 'str', 0, null];
28
+ * const entries: readonly unknown[] = [{ id: 1 }, 'str', 0, null] as const;
29
29
  *
30
30
  * const records = entries.filter(isRecord);
31
31
  *
@@ -58,7 +58,7 @@ export const isRecord = (u: unknown): u is UnknownRecord => isNonNullObject(u);
58
58
  *
59
59
  * @example
60
60
  * ```ts
61
- * const obj: unknown = { foo: 1 };
61
+ * const obj: unknown = { foo: 1 } as const;
62
62
  *
63
63
  * if (isMutableRecord(obj)) {
64
64
  * obj['bar'] = 2; // Safe: obj is now known to be a mutable record
@@ -4,7 +4,7 @@ import { isRecord } from './is-record.mjs';
4
4
  describe(isRecord, () => {
5
5
  describe('arrays are Records', () => {
6
6
  test('number[] is assignable to Record<number, unknown>', () => {
7
- const arr: Record<number, unknown> = [1, 2, 3];
7
+ const arr: Record<number, unknown> = [1, 2, 3] as const;
8
8
 
9
9
  const unk: unknown = arr;
10
10
 
@@ -14,7 +14,7 @@ describe(isRecord, () => {
14
14
  });
15
15
 
16
16
  test('string[] is assignable to Record<number, unknown>', () => {
17
- const arr: Record<number, unknown> = ['1', '2', '3'];
17
+ const arr: Record<number, unknown> = ['1', '2', '3'] as const;
18
18
 
19
19
  const unk: unknown = arr;
20
20
 
@@ -9,7 +9,7 @@
9
9
  * @example
10
10
  *
11
11
  * ```ts
12
- * const values: readonly (number | undefined)[] = [1, undefined, 2];
12
+ * const values: readonly (number | undefined)[] = [1, undefined, 2] as const;
13
13
  *
14
14
  * const undefinedValues = values.filter(isUndefined);
15
15
  *
@@ -34,7 +34,7 @@ export const isUndefined = (u: unknown): u is undefined => u === undefined;
34
34
  * @example
35
35
  *
36
36
  * ```ts
37
- * const values: readonly (number | undefined)[] = [1, undefined, 2];
37
+ * const values: readonly (number | undefined)[] = [1, undefined, 2] as const;
38
38
  *
39
39
  * const definedValues = values.filter(isNotUndefined);
40
40
  *
@@ -60,7 +60,7 @@ export const isNotUndefined = <T,>(u: T): u is RelaxedExclude<T, undefined> =>
60
60
  * @example
61
61
  *
62
62
  * ```ts
63
- * const flags: readonly unknown[] = [true, 'no', false];
63
+ * const flags: readonly unknown[] = [true, 'no', false] as const;
64
64
  *
65
65
  * const booleans = flags.filter(isBoolean);
66
66
  *
@@ -84,7 +84,7 @@ export const isBoolean = (u: unknown): u is boolean => typeof u === 'boolean';
84
84
  * @example
85
85
  *
86
86
  * ```ts
87
- * const flags: readonly unknown[] = [true, 'no', false];
87
+ * const flags: readonly unknown[] = [true, 'no', false] as const;
88
88
  *
89
89
  * const nonBooleans = flags.filter(isNotBoolean);
90
90
  *
@@ -111,7 +111,7 @@ export const isNotBoolean = <T,>(u: T): u is RelaxedExclude<T, boolean> =>
111
111
  * @example
112
112
  *
113
113
  * ```ts
114
- * const mixed: readonly unknown[] = [1, '2', 3];
114
+ * const mixed: readonly unknown[] = [1, '2', 3] as const;
115
115
  *
116
116
  * const numbers = mixed.filter(isNumber);
117
117
  *
@@ -135,7 +135,7 @@ export const isNumber = (u: unknown): u is number => typeof u === 'number';
135
135
  * @example
136
136
  *
137
137
  * ```ts
138
- * const mixed: readonly unknown[] = [1, '2', 3];
138
+ * const mixed: readonly unknown[] = [1, '2', 3] as const;
139
139
  *
140
140
  * const nonNumbers = mixed.filter(isNotNumber);
141
141
  *
@@ -161,7 +161,7 @@ export const isNotNumber = <T,>(u: T): u is RelaxedExclude<T, number> =>
161
161
  * @example
162
162
  *
163
163
  * ```ts
164
- * const values: readonly unknown[] = [1n, 2, 3n];
164
+ * const values: readonly unknown[] = [1n, 2, 3n] as const;
165
165
  *
166
166
  * const bigints = values.filter(isBigint);
167
167
  *
@@ -185,7 +185,7 @@ export const isBigint = (u: unknown): u is bigint => typeof u === 'bigint';
185
185
  * @example
186
186
  *
187
187
  * ```ts
188
- * const values: readonly unknown[] = [1n, 2, 3n];
188
+ * const values: readonly unknown[] = [1n, 2, 3n] as const;
189
189
  *
190
190
  * const nonBigints = values.filter(isNotBigint);
191
191
  *
@@ -212,7 +212,7 @@ export const isNotBigint = <T,>(u: T): u is RelaxedExclude<T, bigint> =>
212
212
  * @example
213
213
  *
214
214
  * ```ts
215
- * const values: readonly unknown[] = ['Ada', 42, 'Lovelace'];
215
+ * const values: readonly unknown[] = ['Ada', 42, 'Lovelace'] as const;
216
216
  *
217
217
  * const strings = values.filter(isString);
218
218
  *
@@ -236,7 +236,7 @@ export const isString = (u: unknown): u is string => typeof u === 'string';
236
236
  * @example
237
237
  *
238
238
  * ```ts
239
- * const values: readonly unknown[] = ['Ada', 42, 'Lovelace'];
239
+ * const values: readonly unknown[] = ['Ada', 42, 'Lovelace'] as const;
240
240
  *
241
241
  * const nonStrings = values.filter(isNotString);
242
242
  *
@@ -266,7 +266,7 @@ export const isNotString = <T,>(u: T): u is RelaxedExclude<T, string> =>
266
266
  *
267
267
  * const shared = Symbol.for('shared');
268
268
  *
269
- * const tokens: readonly unknown[] = [id, 'shared', shared];
269
+ * const tokens: readonly unknown[] = [id, 'shared', shared] as const;
270
270
  *
271
271
  * const symbols = tokens.filter(isSymbol);
272
272
  *
@@ -292,7 +292,7 @@ export const isSymbol = (u: unknown): u is symbol => typeof u === 'symbol';
292
292
  * ```ts
293
293
  * const id = Symbol('id');
294
294
  *
295
- * const tokens: readonly unknown[] = [id, 'shared'];
295
+ * const tokens: readonly unknown[] = [id, 'shared'] as const;
296
296
  *
297
297
  * const nonSymbols = tokens.filter(isNotSymbol);
298
298
  *
@@ -343,7 +343,7 @@ export const isNull = (u: unknown): u is null => u === null;
343
343
  * @example
344
344
  *
345
345
  * ```ts
346
- * const values: readonly (number | null)[] = [null, 5];
346
+ * const values: readonly (number | null)[] = [null, 5] as const;
347
347
  *
348
348
  * const nonNullValues = values.filter(isNotNull);
349
349
  *
@@ -376,7 +376,7 @@ export const isNotNull = <T,>(u: T | null): u is T => u !== null;
376
376
  * 'Ada',
377
377
  * null,
378
378
  * undefined,
379
- * ];
379
+ * ] as const;
380
380
  *
381
381
  * const nullishValues = values.filter(isNullish);
382
382
  *
@@ -409,7 +409,7 @@ export const isNullish = (u: unknown): u is null | undefined => u == null;
409
409
  * 'Ada',
410
410
  * null,
411
411
  * undefined,
412
- * ];
412
+ * ] as const;
413
413
  *
414
414
  * const definedValues = values.filter(isNonNullish);
415
415
  *
@@ -572,7 +572,7 @@ describe(isNonNullish, () => {
572
572
  'world',
573
573
  undefined,
574
574
  'test',
575
- ];
575
+ ] as const;
576
576
 
577
577
  const definedItems = items.filter(isNonNullish);
578
578
 
@@ -618,7 +618,7 @@ describe('type guard behavior in complex scenarios', () => {
618
618
  undefined,
619
619
  false,
620
620
  123,
621
- ];
621
+ ] as const;
622
622
 
623
623
  const nonNullish = mixed.filter(isNonNullish);
624
624
 
@@ -44,4 +44,6 @@ export const keyIsIn = <
44
44
  >(
45
45
  key: K,
46
46
  obj: R,
47
- ): key is K & keyof typeof obj => Object.hasOwn(obj, key);
47
+ ): key is K & keyof typeof obj =>
48
+ // eslint-disable-next-line ts-data-forge/prefer-is-record-and-has-key
49
+ Object.hasOwn(obj, key);
package/src/json/json.mts CHANGED
@@ -93,7 +93,7 @@ export namespace Json {
93
93
  * @example
94
94
  *
95
95
  * ```ts
96
- * const data = { name: 'Bob', age: 25, active: true };
96
+ * const data = { name: 'Bob', age: 25, active: true } as const;
97
97
  *
98
98
  * // Basic stringify
99
99
  * const basic = Json.stringify(data);
@@ -177,7 +177,7 @@ export namespace Json {
177
177
  * email: 'charlie@example.com',
178
178
  * password: 'secret123',
179
179
  * role: 'admin',
180
- * };
180
+ * } as const;
181
181
  *
182
182
  * // Select only safe properties to serialize
183
183
  * const safeJson = Json.stringifySelected(user, ['id', 'name', 'role']);
@@ -262,7 +262,7 @@ export namespace Json {
262
262
  * alpha: 'a',
263
263
  * beta: 'b',
264
264
  * },
265
- * };
265
+ * } as const;
266
266
  *
267
267
  * // Keys will be sorted alphabetically at all levels
268
268
  * const sorted = Json.stringifySortedKey(unorderedData);
@@ -354,6 +354,7 @@ const keysDeepImpl = (
354
354
  keysDeepImpl(o, mut_keys);
355
355
  }
356
356
 
357
+ // eslint-disable-next-line ts-data-forge/prefer-arr-is-array
357
358
  if (Array.isArray(o)) {
358
359
  for (const li of o) {
359
360
  if (isRecord(li)) {