ts-data-forge 6.3.1 → 6.5.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 (182) 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.d.mts +19 -16
  25. package/dist/collections/imap.d.mts.map +1 -1
  26. package/dist/collections/imap.mjs +1 -1
  27. package/dist/collections/imap.mjs.map +1 -1
  28. package/dist/collections/iset-mapped.d.mts +2 -2
  29. package/dist/collections/iset-mapped.d.mts.map +1 -1
  30. package/dist/collections/iset-mapped.mjs.map +1 -1
  31. package/dist/collections/iset.d.mts +1 -1
  32. package/dist/collections/iset.d.mts.map +1 -1
  33. package/dist/collections/iset.mjs +1 -0
  34. package/dist/collections/iset.mjs.map +1 -1
  35. package/dist/entry-point.mjs +1 -0
  36. package/dist/entry-point.mjs.map +1 -1
  37. package/dist/functional/optional/impl/optional-is-optional.d.mts +1 -1
  38. package/dist/functional/optional/impl/optional-is-optional.d.mts.map +1 -1
  39. package/dist/functional/optional/impl/optional-is-optional.mjs +6 -5
  40. package/dist/functional/optional/impl/optional-is-optional.mjs.map +1 -1
  41. package/dist/functional/optional/impl/optional-some.d.mts.map +1 -1
  42. package/dist/functional/optional/impl/optional-some.mjs.map +1 -1
  43. package/dist/functional/optional/impl/optional-zip.d.mts +1 -1
  44. package/dist/functional/optional/impl/optional-zip.mjs +1 -1
  45. package/dist/functional/result/impl/result-err.d.mts.map +1 -1
  46. package/dist/functional/result/impl/result-err.mjs.map +1 -1
  47. package/dist/functional/result/impl/result-is-result.d.mts +1 -1
  48. package/dist/functional/result/impl/result-is-result.mjs +1 -1
  49. package/dist/functional/result/impl/result-ok.d.mts.map +1 -1
  50. package/dist/functional/result/impl/result-ok.mjs.map +1 -1
  51. package/dist/functional/result/impl/result-unwrap-err-throw.mjs +1 -0
  52. package/dist/functional/result/impl/result-unwrap-err-throw.mjs.map +1 -1
  53. package/dist/functional/result/impl/result-unwrap-throw.mjs +1 -0
  54. package/dist/functional/result/impl/result-unwrap-throw.mjs.map +1 -1
  55. package/dist/functional/ternary-result/impl/ternary-result-err.d.mts.map +1 -1
  56. package/dist/functional/ternary-result/impl/ternary-result-err.mjs.map +1 -1
  57. package/dist/functional/ternary-result/impl/ternary-result-is-ternary-result.d.mts +1 -1
  58. package/dist/functional/ternary-result/impl/ternary-result-is-ternary-result.mjs +1 -1
  59. package/dist/functional/ternary-result/impl/ternary-result-ok.d.mts.map +1 -1
  60. package/dist/functional/ternary-result/impl/ternary-result-ok.mjs.map +1 -1
  61. package/dist/functional/ternary-result/impl/ternary-result-unwrap-err-throw.mjs +1 -0
  62. package/dist/functional/ternary-result/impl/ternary-result-unwrap-err-throw.mjs.map +1 -1
  63. package/dist/functional/ternary-result/impl/ternary-result-unwrap-throw.mjs +1 -0
  64. package/dist/functional/ternary-result/impl/ternary-result-unwrap-throw.mjs.map +1 -1
  65. package/dist/functional/ternary-result/impl/ternary-result-unwrap-warn-throw.mjs +1 -0
  66. package/dist/functional/ternary-result/impl/ternary-result-unwrap-warn-throw.mjs.map +1 -1
  67. package/dist/functional/ternary-result/impl/ternary-result-warn.d.mts.map +1 -1
  68. package/dist/functional/ternary-result/impl/ternary-result-warn.mjs.map +1 -1
  69. package/dist/guard/has-key.d.mts +3 -1
  70. package/dist/guard/has-key.d.mts.map +1 -1
  71. package/dist/guard/has-key.mjs +6 -2
  72. package/dist/guard/has-key.mjs.map +1 -1
  73. package/dist/guard/is-non-null-object.d.mts.map +1 -1
  74. package/dist/guard/is-non-null-object.mjs +3 -1
  75. package/dist/guard/is-non-null-object.mjs.map +1 -1
  76. package/dist/guard/is-record.d.mts +2 -2
  77. package/dist/guard/is-record.mjs +2 -2
  78. package/dist/guard/is-type.d.mts +15 -15
  79. package/dist/guard/is-type.mjs +15 -15
  80. package/dist/guard/key-is-in.d.mts.map +1 -1
  81. package/dist/guard/key-is-in.mjs +3 -1
  82. package/dist/guard/key-is-in.mjs.map +1 -1
  83. package/dist/index.mjs +1 -0
  84. package/dist/index.mjs.map +1 -1
  85. package/dist/json/json.d.mts +3 -3
  86. package/dist/json/json.mjs +4 -3
  87. package/dist/json/json.mjs.map +1 -1
  88. package/dist/number/branded-types/non-zero-safe-int.mjs +2 -2
  89. package/dist/number/branded-types/positive-safe-int.mjs +1 -1
  90. package/dist/number/branded-types/safe-int.mjs +2 -2
  91. package/dist/number/branded-types/safe-uint.mjs +1 -1
  92. package/dist/number/num.mjs +1 -1
  93. package/dist/object/object.d.mts +8 -8
  94. package/dist/object/object.d.mts.map +1 -1
  95. package/dist/object/object.mjs +7 -6
  96. package/dist/object/object.mjs.map +1 -1
  97. package/dist/others/fast-deep-equal.d.mts +8 -0
  98. package/dist/others/fast-deep-equal.d.mts.map +1 -0
  99. package/dist/others/fast-deep-equal.mjs +72 -0
  100. package/dist/others/fast-deep-equal.mjs.map +1 -0
  101. package/dist/others/index.d.mts +1 -0
  102. package/dist/others/index.d.mts.map +1 -1
  103. package/dist/others/index.mjs +1 -0
  104. package/dist/others/index.mjs.map +1 -1
  105. package/dist/others/memoize-function.d.mts +3 -2
  106. package/dist/others/memoize-function.d.mts.map +1 -1
  107. package/dist/others/memoize-function.mjs +10 -39
  108. package/dist/others/memoize-function.mjs.map +1 -1
  109. package/package.json +22 -17
  110. package/src/array/impl/array-utils-creation.test.mts +13 -10
  111. package/src/array/impl/array-utils-element-access.mts +5 -5
  112. package/src/array/impl/array-utils-element-access.test.mts +5 -5
  113. package/src/array/impl/array-utils-iterators.mts +1 -1
  114. package/src/array/impl/array-utils-iterators.test.mts +6 -6
  115. package/src/array/impl/array-utils-modification.mts +4 -4
  116. package/src/array/impl/array-utils-modification.test.mts +12 -12
  117. package/src/array/impl/array-utils-overload-type-error.test.mts +1 -1
  118. package/src/array/impl/array-utils-reducing-value.mts +6 -5
  119. package/src/array/impl/array-utils-reducing-value.test.mts +9 -9
  120. package/src/array/impl/array-utils-search.mts +8 -8
  121. package/src/array/impl/array-utils-search.test.mts +35 -35
  122. package/src/array/impl/array-utils-set-op.mts +1 -0
  123. package/src/array/impl/array-utils-set-op.test.mts +2 -2
  124. package/src/array/impl/array-utils-size.mts +1 -1
  125. package/src/array/impl/array-utils-size.test.mts +1 -1
  126. package/src/array/impl/array-utils-slice-clamped.mts +1 -1
  127. package/src/array/impl/array-utils-slice-clamped.test.mts +5 -5
  128. package/src/array/impl/array-utils-slicing.mts +3 -3
  129. package/src/array/impl/array-utils-slicing.test.mts +5 -5
  130. package/src/array/impl/array-utils-transformation.mts +1 -1
  131. package/src/array/impl/array-utils-transformation.test.mts +53 -53
  132. package/src/array/impl/array-utils-validation.mts +18 -10
  133. package/src/array/impl/array-utils-validation.test.mts +34 -29
  134. package/src/array/impl/array.test.mts +1 -1
  135. package/src/collections/imap-mapped.test.mts +9 -9
  136. package/src/collections/imap.mts +20 -17
  137. package/src/collections/imap.test.mts +6 -6
  138. package/src/collections/iset-mapped.mts +7 -6
  139. package/src/collections/iset-mapped.test.mts +6 -6
  140. package/src/collections/iset.mts +6 -5
  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 +9 -8
  173. package/src/object/object.test.mts +12 -7
  174. package/src/others/cast-mutable.test.mts +3 -3
  175. package/src/others/cast-readonly.test.mts +8 -5
  176. package/src/others/fast-deep-equal.mts +98 -0
  177. package/src/others/fast-deep-equal.test.mts +769 -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.mts +35 -17
  181. package/src/others/memoize-function.test.mts +45 -8
  182. package/src/others/unknown-to-string.test.mts +8 -8
@@ -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)) {
@@ -54,7 +54,7 @@ describe('parse', () => {
54
54
  array: [1, 2, { level3: 'deep' }],
55
55
  },
56
56
  },
57
- };
57
+ } as const;
58
58
 
59
59
  assert.deepStrictEqual(Json.parse(json), Result.ok(expected));
60
60
  });
@@ -227,7 +227,7 @@ describe('stringify', () => {
227
227
  array: [1, 2, { level3: 'deep' }],
228
228
  },
229
229
  },
230
- };
230
+ } as const;
231
231
 
232
232
  assert.deepStrictEqual(
233
233
  Json.stringify(nested),
@@ -301,7 +301,7 @@ describe('stringify', () => {
301
301
  test('should handle objects with toJSON method', () => {
302
302
  const obj = {
303
303
  toJSON: () => ({ custom: 'value' }),
304
- };
304
+ } as const;
305
305
 
306
306
  assert.deepStrictEqual(
307
307
  Json.stringify(obj),
@@ -333,7 +333,7 @@ describe('stringify', () => {
333
333
  name: 'John',
334
334
  password: 'secret123',
335
335
  email: 'john@example.com',
336
- };
336
+ } as const;
337
337
 
338
338
  const secureReplacer = (key: string, value: unknown): unknown => {
339
339
  if (key === 'password') return '[REDACTED]';
@@ -351,7 +351,7 @@ describe('stringify', () => {
351
351
  });
352
352
 
353
353
  test('should format output with space parameter (number)', () => {
354
- const data = { a: 1, b: 2 };
354
+ const data = { a: 1, b: 2 } as const;
355
355
 
356
356
  const result = Json.stringify(data, undefined, 2);
357
357
 
@@ -363,7 +363,7 @@ describe('stringify', () => {
363
363
  });
364
364
 
365
365
  test('should format output with space parameter (string)', () => {
366
- const data = { a: 1, b: 2 };
366
+ const data = { a: 1, b: 2 } as const;
367
367
 
368
368
  const result = Json.stringify(data, undefined, '\t');
369
369
 
@@ -383,7 +383,7 @@ describe('stringifySelected', () => {
383
383
  email: 'alice@example.com',
384
384
  password: 'secret123',
385
385
  lastLogin: '2023-12-01',
386
- };
386
+ } as const;
387
387
 
388
388
  const result = Json.stringifySelected(user, ['id', 'name', 'email']);
389
389
 
@@ -411,7 +411,7 @@ describe('stringifySelected', () => {
411
411
  { id: 2, name: 'Bob', secret: 'hidden2' },
412
412
  ],
413
413
  metadata: { total: 2, page: 1, internal: 'secret' },
414
- };
414
+ } as const;
415
415
 
416
416
  const result = Json.stringifySelected(data, [
417
417
  'users',
@@ -453,7 +453,7 @@ describe('stringifySelected', () => {
453
453
  [1, 2, 3, 4],
454
454
  [5, 6, 7, 8],
455
455
  [9, 10, 11, 12],
456
- ];
456
+ ] as const;
457
457
 
458
458
  const result = Json.stringifySelected(matrix, [0, 1]);
459
459
 
@@ -465,13 +465,14 @@ describe('stringifySelected', () => {
465
465
 
466
466
  // Note: stringifySelected works with JSON.stringify's replacer parameter
467
467
  // which may not work as expected with arrays
468
+ // eslint-disable-next-line ts-data-forge/prefer-arr-is-array
468
469
  assert.isTrue(Array.isArray(parsed));
469
470
 
470
471
  expect(parsed).toHaveLength(3);
471
472
  });
472
473
 
473
474
  test('should handle formatting with space parameter', () => {
474
- const data = { a: 1, b: { c: 2 } };
475
+ const data = { a: 1, b: { c: 2 } } as const;
475
476
 
476
477
  const result = Json.stringifySelected(data, ['a', 'b', 'c'], 2);
477
478
 
@@ -483,7 +484,7 @@ describe('stringifySelected', () => {
483
484
  });
484
485
 
485
486
  test('should handle empty selection array', () => {
486
- const data = { a: 1, b: 2, c: 3 };
487
+ const data = { a: 1, b: 2, c: 3 } as const;
487
488
 
488
489
  const result = Json.stringifySelected(data, []);
489
490
 
@@ -493,7 +494,7 @@ describe('stringifySelected', () => {
493
494
  });
494
495
 
495
496
  test('should handle undefined properties parameter', () => {
496
- const data = { a: 1, b: 2 };
497
+ const data = { a: 1, b: 2 } as const;
497
498
 
498
499
  const result = Json.stringifySelected(data, undefined);
499
500
 
@@ -532,7 +533,7 @@ describe('stringifySortedKey', () => {
532
533
  apple: 'fruit',
533
534
  banana: 'fruit',
534
535
  aardvark: 'animal',
535
- };
536
+ } as const;
536
537
 
537
538
  const result = Json.stringifySortedKey(unsortedObj);
538
539
 
@@ -558,7 +559,7 @@ describe('stringifySortedKey', () => {
558
559
  theme: 'dark',
559
560
  language: 'en',
560
561
  },
561
- };
562
+ } as const;
562
563
 
563
564
  const result = Json.stringifySortedKey(nestedObj);
564
565
 
@@ -598,7 +599,7 @@ describe('stringifySortedKey', () => {
598
599
  created: '2023-12-01',
599
600
  author: 'system',
600
601
  },
601
- };
602
+ } as const;
602
603
 
603
604
  const result = Json.stringifySortedKey(dataWithArrays);
604
605
 
@@ -639,7 +640,7 @@ describe('stringifySortedKey', () => {
639
640
  });
640
641
 
641
642
  test('should handle formatting with space parameter', () => {
642
- const obj = { b: 2, a: 1 };
643
+ const obj = { b: 2, a: 1 } as const;
643
644
 
644
645
  const result = Json.stringifySortedKey(obj, 2);
645
646
 
@@ -653,9 +654,9 @@ describe('stringifySortedKey', () => {
653
654
  });
654
655
 
655
656
  test('should produce deterministic output', () => {
656
- const obj1 = { c: 3, a: 1, b: 2 };
657
+ const obj1 = { c: 3, a: 1, b: 2 } as const;
657
658
 
658
- const obj2 = { b: 2, a: 1, c: 3 };
659
+ const obj2 = { b: 2, a: 1, c: 3 } as const;
659
660
 
660
661
  const result1 = Json.stringifySortedKey(obj1);
661
662
 
@@ -716,7 +717,7 @@ describe('stringifySortedKey', () => {
716
717
  },
717
718
  },
718
719
  },
719
- };
720
+ } as const;
720
721
 
721
722
  const result = Json.stringifySortedKey(deep);
722
723
 
@@ -27,9 +27,9 @@ const {
27
27
  >({
28
28
  integerOrSafeInteger: 'SafeInteger',
29
29
  nonZero: true,
30
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion, math/prefer-number-min-safe-integer
30
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion, math/prefer-number-min-safe-integer, ts-data-forge/prefer-as-int
31
31
  MIN_VALUE: Number.MIN_SAFE_INTEGER as SafeInt,
32
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion, math/prefer-number-max-safe-integer
32
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion, math/prefer-number-max-safe-integer, ts-data-forge/prefer-as-int
33
33
  MAX_VALUE: Number.MAX_SAFE_INTEGER as SafeUint,
34
34
  typeNameInMessage,
35
35
  } as const);
@@ -26,7 +26,7 @@ const {
26
26
  >({
27
27
  integerOrSafeInteger: 'SafeInteger',
28
28
  MIN_VALUE: 1,
29
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion, math/prefer-number-max-safe-integer
29
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion, math/prefer-number-max-safe-integer, ts-data-forge/prefer-as-int
30
30
  MAX_VALUE: Number.MAX_SAFE_INTEGER as SafeUint,
31
31
  typeNameInMessage,
32
32
  } as const);