ts-data-forge 1.0.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 (143) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +534 -0
  3. package/package.json +101 -0
  4. package/src/array/array-utils-creation.test.mts +443 -0
  5. package/src/array/array-utils-modification.test.mts +197 -0
  6. package/src/array/array-utils-overload-type-error.test.mts +149 -0
  7. package/src/array/array-utils-reducing-value.test.mts +425 -0
  8. package/src/array/array-utils-search.test.mts +169 -0
  9. package/src/array/array-utils-set-op.test.mts +335 -0
  10. package/src/array/array-utils-slice-clamped.test.mts +113 -0
  11. package/src/array/array-utils-slicing.test.mts +316 -0
  12. package/src/array/array-utils-transformation.test.mts +790 -0
  13. package/src/array/array-utils-validation.test.mts +492 -0
  14. package/src/array/array-utils.mts +4000 -0
  15. package/src/array/array.test.mts +146 -0
  16. package/src/array/index.mts +2 -0
  17. package/src/array/tuple-utils.mts +519 -0
  18. package/src/array/tuple-utils.test.mts +518 -0
  19. package/src/collections/imap-mapped.mts +801 -0
  20. package/src/collections/imap-mapped.test.mts +860 -0
  21. package/src/collections/imap.mts +651 -0
  22. package/src/collections/imap.test.mts +932 -0
  23. package/src/collections/index.mts +6 -0
  24. package/src/collections/iset-mapped.mts +889 -0
  25. package/src/collections/iset-mapped.test.mts +1187 -0
  26. package/src/collections/iset.mts +682 -0
  27. package/src/collections/iset.test.mts +1084 -0
  28. package/src/collections/queue.mts +390 -0
  29. package/src/collections/queue.test.mts +282 -0
  30. package/src/collections/stack.mts +423 -0
  31. package/src/collections/stack.test.mts +225 -0
  32. package/src/expect-type.mts +206 -0
  33. package/src/functional/index.mts +4 -0
  34. package/src/functional/match.mts +300 -0
  35. package/src/functional/match.test.mts +177 -0
  36. package/src/functional/optional.mts +733 -0
  37. package/src/functional/optional.test.mts +619 -0
  38. package/src/functional/pipe.mts +212 -0
  39. package/src/functional/pipe.test.mts +85 -0
  40. package/src/functional/result.mts +1134 -0
  41. package/src/functional/result.test.mts +777 -0
  42. package/src/globals.d.mts +38 -0
  43. package/src/guard/has-key.mts +119 -0
  44. package/src/guard/has-key.test.mts +219 -0
  45. package/src/guard/index.mts +7 -0
  46. package/src/guard/is-non-empty-string.mts +108 -0
  47. package/src/guard/is-non-empty-string.test.mts +91 -0
  48. package/src/guard/is-non-null-object.mts +106 -0
  49. package/src/guard/is-non-null-object.test.mts +90 -0
  50. package/src/guard/is-primitive.mts +165 -0
  51. package/src/guard/is-primitive.test.mts +102 -0
  52. package/src/guard/is-record.mts +153 -0
  53. package/src/guard/is-record.test.mts +112 -0
  54. package/src/guard/is-type.mts +450 -0
  55. package/src/guard/is-type.test.mts +496 -0
  56. package/src/guard/key-is-in.mts +163 -0
  57. package/src/guard/key-is-in.test.mts +19 -0
  58. package/src/index.mts +10 -0
  59. package/src/iterator/index.mts +1 -0
  60. package/src/iterator/range.mts +120 -0
  61. package/src/iterator/range.test.mts +33 -0
  62. package/src/json/index.mts +1 -0
  63. package/src/json/json.mts +711 -0
  64. package/src/json/json.test.mts +628 -0
  65. package/src/number/branded-types/finite-number.mts +354 -0
  66. package/src/number/branded-types/finite-number.test.mts +135 -0
  67. package/src/number/branded-types/index.mts +26 -0
  68. package/src/number/branded-types/int.mts +278 -0
  69. package/src/number/branded-types/int.test.mts +140 -0
  70. package/src/number/branded-types/int16.mts +192 -0
  71. package/src/number/branded-types/int16.test.mts +170 -0
  72. package/src/number/branded-types/int32.mts +193 -0
  73. package/src/number/branded-types/int32.test.mts +170 -0
  74. package/src/number/branded-types/non-negative-finite-number.mts +223 -0
  75. package/src/number/branded-types/non-negative-finite-number.test.mts +188 -0
  76. package/src/number/branded-types/non-negative-int16.mts +187 -0
  77. package/src/number/branded-types/non-negative-int16.test.mts +201 -0
  78. package/src/number/branded-types/non-negative-int32.mts +187 -0
  79. package/src/number/branded-types/non-negative-int32.test.mts +204 -0
  80. package/src/number/branded-types/non-zero-finite-number.mts +229 -0
  81. package/src/number/branded-types/non-zero-finite-number.test.mts +198 -0
  82. package/src/number/branded-types/non-zero-int.mts +167 -0
  83. package/src/number/branded-types/non-zero-int.test.mts +177 -0
  84. package/src/number/branded-types/non-zero-int16.mts +196 -0
  85. package/src/number/branded-types/non-zero-int16.test.mts +195 -0
  86. package/src/number/branded-types/non-zero-int32.mts +196 -0
  87. package/src/number/branded-types/non-zero-int32.test.mts +197 -0
  88. package/src/number/branded-types/non-zero-safe-int.mts +196 -0
  89. package/src/number/branded-types/non-zero-safe-int.test.mts +232 -0
  90. package/src/number/branded-types/non-zero-uint16.mts +189 -0
  91. package/src/number/branded-types/non-zero-uint16.test.mts +199 -0
  92. package/src/number/branded-types/non-zero-uint32.mts +189 -0
  93. package/src/number/branded-types/non-zero-uint32.test.mts +199 -0
  94. package/src/number/branded-types/positive-finite-number.mts +241 -0
  95. package/src/number/branded-types/positive-finite-number.test.mts +204 -0
  96. package/src/number/branded-types/positive-int.mts +304 -0
  97. package/src/number/branded-types/positive-int.test.mts +176 -0
  98. package/src/number/branded-types/positive-int16.mts +188 -0
  99. package/src/number/branded-types/positive-int16.test.mts +197 -0
  100. package/src/number/branded-types/positive-int32.mts +188 -0
  101. package/src/number/branded-types/positive-int32.test.mts +197 -0
  102. package/src/number/branded-types/positive-safe-int.mts +187 -0
  103. package/src/number/branded-types/positive-safe-int.test.mts +210 -0
  104. package/src/number/branded-types/positive-uint16.mts +188 -0
  105. package/src/number/branded-types/positive-uint16.test.mts +203 -0
  106. package/src/number/branded-types/positive-uint32.mts +188 -0
  107. package/src/number/branded-types/positive-uint32.test.mts +203 -0
  108. package/src/number/branded-types/safe-int.mts +291 -0
  109. package/src/number/branded-types/safe-int.test.mts +170 -0
  110. package/src/number/branded-types/safe-uint.mts +187 -0
  111. package/src/number/branded-types/safe-uint.test.mts +176 -0
  112. package/src/number/branded-types/uint.mts +179 -0
  113. package/src/number/branded-types/uint.test.mts +158 -0
  114. package/src/number/branded-types/uint16.mts +186 -0
  115. package/src/number/branded-types/uint16.test.mts +170 -0
  116. package/src/number/branded-types/uint32.mts +218 -0
  117. package/src/number/branded-types/uint32.test.mts +170 -0
  118. package/src/number/enum/index.mts +2 -0
  119. package/src/number/enum/int8.mts +344 -0
  120. package/src/number/enum/int8.test.mts +180 -0
  121. package/src/number/enum/uint8.mts +293 -0
  122. package/src/number/enum/uint8.test.mts +164 -0
  123. package/src/number/index.mts +4 -0
  124. package/src/number/num.mts +604 -0
  125. package/src/number/num.test.mts +242 -0
  126. package/src/number/refined-number-utils.mts +566 -0
  127. package/src/object/index.mts +1 -0
  128. package/src/object/object.mts +447 -0
  129. package/src/object/object.test.mts +124 -0
  130. package/src/others/cast-mutable.mts +113 -0
  131. package/src/others/cast-readonly.mts +192 -0
  132. package/src/others/cast-readonly.test.mts +89 -0
  133. package/src/others/if-then.mts +98 -0
  134. package/src/others/if-then.test.mts +75 -0
  135. package/src/others/index.mts +7 -0
  136. package/src/others/map-nullable.mts +172 -0
  137. package/src/others/map-nullable.test.mts +297 -0
  138. package/src/others/memoize-function.mts +196 -0
  139. package/src/others/memoize-function.test.mts +168 -0
  140. package/src/others/tuple.mts +160 -0
  141. package/src/others/tuple.test.mts +11 -0
  142. package/src/others/unknown-to-string.mts +215 -0
  143. package/src/others/unknown-to-string.test.mts +114 -0
@@ -0,0 +1,354 @@
1
+ import { expectType } from '../../expect-type.mjs';
2
+ import { TsVerifiedInternals } from '../refined-number-utils.mjs';
3
+
4
+ type ElementType = FiniteNumber;
5
+
6
+ const typeNameInMessage = 'a finite number';
7
+
8
+ const {
9
+ abs,
10
+ min: min_,
11
+ max: max_,
12
+ pow,
13
+ add,
14
+ sub,
15
+ mul,
16
+ div,
17
+ random,
18
+ is,
19
+ castType,
20
+ } = TsVerifiedInternals.RefinedNumberUtils.operatorsForFloat<
21
+ ElementType,
22
+ undefined,
23
+ undefined
24
+ >({
25
+ MIN_VALUE: undefined,
26
+ MAX_VALUE: undefined,
27
+ typeNameInMessage,
28
+ } as const);
29
+
30
+ const floor = (
31
+ x: ElementType,
32
+ ): TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType> =>
33
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
34
+ Math.floor(x) as TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>;
35
+
36
+ const ceil = (
37
+ x: ElementType,
38
+ ): TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType> =>
39
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
40
+ Math.ceil(x) as TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>;
41
+
42
+ const round = (
43
+ x: ElementType,
44
+ ): TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType> =>
45
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
46
+ Math.round(x) as TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>;
47
+
48
+ expectType<TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>, Int>('=');
49
+
50
+ /**
51
+ * Type guard that checks if a value is a finite number.
52
+ *
53
+ * Returns `true` if the value is a finite number (not NaN, Infinity, or -Infinity).
54
+ * This is stricter than the standard number type, which includes these special values.
55
+ *
56
+ * @param value - The value to check
57
+ * @returns `true` if the value is finite, `false` otherwise
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * isFiniteNumber(42); // true
62
+ * isFiniteNumber(3.14); // true
63
+ * isFiniteNumber(-0); // true
64
+ * isFiniteNumber(Infinity); // false
65
+ * isFiniteNumber(-Infinity); // false
66
+ * isFiniteNumber(NaN); // false
67
+ * isFiniteNumber(1/0); // false (Infinity)
68
+ * ```
69
+ */
70
+ export const isFiniteNumber = is;
71
+
72
+ /**
73
+ * Casts a number to a FiniteNumber branded type.
74
+ *
75
+ * This function validates that the input is finite (not NaN, Infinity, or -Infinity)
76
+ * and returns it with the FiniteNumber brand. This ensures type safety for operations
77
+ * that require finite numeric values.
78
+ *
79
+ * @param value - The value to cast
80
+ * @returns The value as a FiniteNumber branded type
81
+ * @throws {TypeError} If the value is NaN, Infinity, or -Infinity
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * const x = asFiniteNumber(5.5); // FiniteNumber
86
+ * const y = asFiniteNumber(-10); // FiniteNumber
87
+ * const z = asFiniteNumber(0); // FiniteNumber
88
+ *
89
+ * // These throw TypeError:
90
+ * // asFiniteNumber(Infinity); // Not finite
91
+ * // asFiniteNumber(-Infinity); // Not finite
92
+ * // asFiniteNumber(NaN); // Not a number
93
+ * // asFiniteNumber(Math.sqrt(-1)); // Results in NaN
94
+ * ```
95
+ */
96
+ export const asFiniteNumber = castType;
97
+
98
+ /**
99
+ * Namespace providing type-safe operations for FiniteNumber branded types.
100
+ *
101
+ * The FiniteNumber type represents any finite numeric value, excluding the
102
+ * special values NaN, Infinity, and -Infinity. All operations are guaranteed
103
+ * to maintain the finite constraint when given finite inputs.
104
+ *
105
+ * This type is essential for:
106
+ * - Mathematical operations that require real numbers
107
+ * - Preventing NaN/Infinity propagation in calculations
108
+ * - Ensuring numeric stability in algorithms
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * // Type validation
113
+ * FiniteNumber.is(3.14); // true
114
+ * FiniteNumber.is(Infinity); // false
115
+ * FiniteNumber.is(0/0); // false (NaN)
116
+ *
117
+ * // Arithmetic with guaranteed finite results
118
+ * const a = asFiniteNumber(10.5);
119
+ * const b = asFiniteNumber(3.2);
120
+ *
121
+ * const sum = FiniteNumber.add(a, b); // FiniteNumber (13.7)
122
+ * const diff = FiniteNumber.sub(a, b); // FiniteNumber (7.3)
123
+ * const product = FiniteNumber.mul(a, b); // FiniteNumber (33.6)
124
+ * const quotient = FiniteNumber.div(a, b); // FiniteNumber (3.28125)
125
+ * const power = FiniteNumber.pow(a, asFiniteNumber(2)); // FiniteNumber (110.25)
126
+ *
127
+ * // Rounding to integers
128
+ * const value = asFiniteNumber(5.7);
129
+ * const floored = FiniteNumber.floor(value); // Int (5)
130
+ * const ceiled = FiniteNumber.ceil(value); // Int (6)
131
+ * const rounded = FiniteNumber.round(value); // Int (6)
132
+ *
133
+ * // Utility operations
134
+ * const absolute = FiniteNumber.abs(asFiniteNumber(-42.5)); // FiniteNumber (42.5)
135
+ * const minimum = FiniteNumber.min(a, b, asFiniteNumber(5)); // FiniteNumber (3.2)
136
+ * const maximum = FiniteNumber.max(a, b, asFiniteNumber(5)); // FiniteNumber (10.5)
137
+ *
138
+ * // Random generation
139
+ * const rand = FiniteNumber.random(asFiniteNumber(0), asFiniteNumber(1)); // Random in [0, 1]
140
+ * ```
141
+ */
142
+ export const FiniteNumber = {
143
+ /**
144
+ * Type guard that checks if a value is a finite number.
145
+ *
146
+ * @param value - The value to check
147
+ * @returns `true` if the value is finite, `false` otherwise
148
+ *
149
+ * @see {@link isFiniteNumber} for usage examples
150
+ */
151
+ is,
152
+
153
+ /**
154
+ * Returns the absolute value of a finite number.
155
+ * @param x - The finite number to get the absolute value of
156
+ * @returns The absolute value as a FiniteNumber
157
+ * @example
158
+ * ```typescript
159
+ * FiniteNumber.abs(asFiniteNumber(-5.5)); // FiniteNumber (5.5)
160
+ * FiniteNumber.abs(asFiniteNumber(3.2)); // FiniteNumber (3.2)
161
+ * ```
162
+ */
163
+ abs,
164
+
165
+ /**
166
+ * Returns the minimum value from a list of finite numbers.
167
+ *
168
+ * @param values - The finite numbers to compare (at least one required)
169
+ * @returns The smallest value as a FiniteNumber
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * const a = asFiniteNumber(5.5);
174
+ * const b = asFiniteNumber(3.2);
175
+ * const c = asFiniteNumber(7.8);
176
+ *
177
+ * FiniteNumber.min(a, b); // FiniteNumber (3.2)
178
+ * FiniteNumber.min(a, b, c); // FiniteNumber (3.2)
179
+ * ```
180
+ */
181
+ min: min_,
182
+
183
+ /**
184
+ * Returns the maximum value from a list of finite numbers.
185
+ *
186
+ * @param values - The finite numbers to compare (at least one required)
187
+ * @returns The largest value as a FiniteNumber
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * const a = asFiniteNumber(5.5);
192
+ * const b = asFiniteNumber(3.2);
193
+ * const c = asFiniteNumber(7.8);
194
+ *
195
+ * FiniteNumber.max(a, b); // FiniteNumber (7.8)
196
+ * FiniteNumber.max(a, b, c); // FiniteNumber (7.8)
197
+ * ```
198
+ */
199
+ max: max_,
200
+
201
+ /**
202
+ * Returns the largest integer less than or equal to the given finite number.
203
+ * @param x - The finite number to floor
204
+ * @returns The floor value as an Int
205
+ * @example
206
+ * ```typescript
207
+ * FiniteNumber.floor(asFiniteNumber(5.8)); // Int (5)
208
+ * FiniteNumber.floor(asFiniteNumber(-5.2)); // Int (-6)
209
+ * ```
210
+ */
211
+ floor,
212
+
213
+ /**
214
+ * Returns the smallest integer greater than or equal to the given finite number.
215
+ * @param x - The finite number to ceil
216
+ * @returns The ceiling value as an Int
217
+ * @example
218
+ * ```typescript
219
+ * FiniteNumber.ceil(asFiniteNumber(5.2)); // Int (6)
220
+ * FiniteNumber.ceil(asFiniteNumber(-5.8)); // Int (-5)
221
+ * ```
222
+ */
223
+ ceil,
224
+
225
+ /**
226
+ * Rounds a finite number to the nearest integer.
227
+ * @param x - The finite number to round
228
+ * @returns The rounded value as an Int
229
+ * @example
230
+ * ```typescript
231
+ * FiniteNumber.round(asFiniteNumber(5.4)); // Int (5)
232
+ * FiniteNumber.round(asFiniteNumber(5.6)); // Int (6)
233
+ * FiniteNumber.round(asFiniteNumber(5.5)); // Int (6)
234
+ * ```
235
+ */
236
+ round,
237
+
238
+ /**
239
+ * Generates a random finite number within the specified range.
240
+ *
241
+ * The generated value is uniformly distributed in the range [min, max].
242
+ * Both bounds are inclusive.
243
+ *
244
+ * @param min - The minimum value (inclusive)
245
+ * @param max - The maximum value (inclusive)
246
+ * @returns A random FiniteNumber in the range [min, max]
247
+ *
248
+ * @example
249
+ * ```typescript
250
+ * // Random percentage (0-100)
251
+ * const pct = FiniteNumber.random(
252
+ * asFiniteNumber(0),
253
+ * asFiniteNumber(100)
254
+ * );
255
+ *
256
+ * // Random coordinate (-1 to 1)
257
+ * const coord = FiniteNumber.random(
258
+ * asFiniteNumber(-1),
259
+ * asFiniteNumber(1)
260
+ * );
261
+ * ```
262
+ */
263
+ random,
264
+
265
+ /**
266
+ * Raises a finite number to a power.
267
+ * @param a - The base finite number
268
+ * @param b - The exponent finite number
269
+ * @returns `a ** b` as a FiniteNumber
270
+ * @example
271
+ * ```typescript
272
+ * FiniteNumber.pow(asFiniteNumber(2.5), asFiniteNumber(3)); // FiniteNumber (15.625)
273
+ * ```
274
+ */
275
+ pow,
276
+
277
+ /**
278
+ * Adds two finite numbers.
279
+ * @param a - First finite number
280
+ * @param b - Second finite number
281
+ * @returns `a + b` as a FiniteNumber
282
+ * @example
283
+ * ```typescript
284
+ * FiniteNumber.add(asFiniteNumber(5.5), asFiniteNumber(3.2)); // FiniteNumber (8.7)
285
+ * ```
286
+ */
287
+ add,
288
+
289
+ /**
290
+ * Subtracts two finite numbers.
291
+ * @param a - First finite number
292
+ * @param b - Second finite number
293
+ * @returns `a - b` as a FiniteNumber
294
+ * @example
295
+ * ```typescript
296
+ * FiniteNumber.sub(asFiniteNumber(8.7), asFiniteNumber(3.2)); // FiniteNumber (5.5)
297
+ * ```
298
+ */
299
+ sub,
300
+
301
+ /**
302
+ * Multiplies two finite numbers.
303
+ * @param a - First finite number
304
+ * @param b - Second finite number
305
+ * @returns `a * b` as a FiniteNumber
306
+ * @example
307
+ * ```typescript
308
+ * FiniteNumber.mul(asFiniteNumber(5.5), asFiniteNumber(2)); // FiniteNumber (11)
309
+ * ```
310
+ */
311
+ mul,
312
+
313
+ /**
314
+ * Divides two finite numbers.
315
+ *
316
+ * The divisor must be non-zero (enforced by type constraints).
317
+ * The result is guaranteed to be finite when both inputs are finite
318
+ * and the divisor is non-zero.
319
+ *
320
+ * @param a - The dividend
321
+ * @param b - The divisor (must be non-zero)
322
+ * @returns The quotient `a / b` as a FiniteNumber
323
+ *
324
+ * @example
325
+ * ```typescript
326
+ * const a = asFiniteNumber(11);
327
+ * const b = asFiniteNumber(2);
328
+ *
329
+ * FiniteNumber.div(a, b); // FiniteNumber (5.5)
330
+ *
331
+ * // With non-zero type guard
332
+ * const divisor = asFiniteNumber(userInput);
333
+ * if (Num.isNonZero(divisor)) {
334
+ * const result = FiniteNumber.div(a, divisor);
335
+ * }
336
+ * ```
337
+ */
338
+ div,
339
+ } as const;
340
+
341
+ expectType<
342
+ TsVerifiedInternals.RefinedNumberUtils.ToNonNegative<ElementType>,
343
+ NonNegativeFiniteNumber
344
+ >('=');
345
+
346
+ expectType<
347
+ keyof typeof FiniteNumber,
348
+ keyof TsVerifiedInternals.RefinedNumberUtils.NumberClass<ElementType, never>
349
+ >('=');
350
+
351
+ expectType<
352
+ typeof FiniteNumber,
353
+ TsVerifiedInternals.RefinedNumberUtils.NumberClass<ElementType, never>
354
+ >('<=');
@@ -0,0 +1,135 @@
1
+ import { expectType } from '../../expect-type.mjs';
2
+ import { asFiniteNumber, FiniteNumber } from './finite-number.mjs';
3
+ import { asNonZeroFiniteNumber } from './non-zero-finite-number.mjs';
4
+
5
+ describe('FiniteNumber', () => {
6
+ describe('asFiniteNumber', () => {
7
+ test('accepts valid finite numbers', () => {
8
+ expect(() => asFiniteNumber(0)).not.toThrow();
9
+ expect(() => asFiniteNumber(1)).not.toThrow();
10
+ expect(() => asFiniteNumber(-1)).not.toThrow();
11
+ expect(() => asFiniteNumber(3.14)).not.toThrow();
12
+ expect(() => asFiniteNumber(-2.5)).not.toThrow();
13
+ expect(() => asFiniteNumber(Number.MAX_VALUE)).not.toThrow();
14
+ expect(() => asFiniteNumber(-Number.MAX_VALUE)).not.toThrow();
15
+ });
16
+
17
+ test('rejects non-finite numbers', () => {
18
+ expect(() => asFiniteNumber(Number.NaN)).toThrow(TypeError);
19
+ expect(() => asFiniteNumber(Number.POSITIVE_INFINITY)).toThrow(TypeError);
20
+ expect(() => asFiniteNumber(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
21
+ });
22
+
23
+ test('returns the same value for valid inputs', () => {
24
+ expect(asFiniteNumber(5.5)).toBe(5.5);
25
+ expect(asFiniteNumber(-10)).toBe(-10);
26
+ expect(asFiniteNumber(0)).toBe(0);
27
+ });
28
+
29
+ test.each([
30
+ { name: 'Number.NaN', value: Number.NaN },
31
+ { name: 'Number.POSITIVE_INFINITY', value: Number.POSITIVE_INFINITY },
32
+ { name: 'Number.NEGATIVE_INFINITY', value: Number.NEGATIVE_INFINITY },
33
+ ] as const)(
34
+ `asFiniteNumber($name) should throw a TypeError`,
35
+ ({ value }) => {
36
+ expect(() => asFiniteNumber(value)).toThrow(
37
+ new TypeError(`Expected a finite number, got: ${value}`),
38
+ );
39
+ },
40
+ );
41
+ });
42
+
43
+ describe('FiniteNumber.is', () => {
44
+ test('correctly identifies finite numbers', () => {
45
+ expect(FiniteNumber.is(0)).toBe(true);
46
+ expect(FiniteNumber.is(1)).toBe(true);
47
+ expect(FiniteNumber.is(-1)).toBe(true);
48
+ expect(FiniteNumber.is(3.14)).toBe(true);
49
+ expect(FiniteNumber.is(-2.5)).toBe(true);
50
+ expect(FiniteNumber.is(Number.MAX_VALUE)).toBe(true);
51
+ expect(FiniteNumber.is(-Number.MAX_VALUE)).toBe(true);
52
+ });
53
+
54
+ test('correctly identifies non-finite numbers', () => {
55
+ expect(FiniteNumber.is(Number.NaN)).toBe(false);
56
+ expect(FiniteNumber.is(Number.POSITIVE_INFINITY)).toBe(false);
57
+ expect(FiniteNumber.is(Number.NEGATIVE_INFINITY)).toBe(false);
58
+ });
59
+ });
60
+
61
+ describe('mathematical operations', () => {
62
+ const a = asFiniteNumber(5.5);
63
+ const b = asFiniteNumber(2.5);
64
+ const c = asFiniteNumber(-3.5);
65
+
66
+ test('abs', () => {
67
+ expect(FiniteNumber.abs(a)).toBe(5.5);
68
+ expect(FiniteNumber.abs(c)).toBe(3.5);
69
+ expect(FiniteNumber.abs(asFiniteNumber(0))).toBe(0);
70
+ });
71
+
72
+ test('min and max', () => {
73
+ expect(FiniteNumber.min(a, b)).toBe(2.5);
74
+ expect(FiniteNumber.max(a, b)).toBe(5.5);
75
+ expect(FiniteNumber.min(a, c)).toBe(-3.5);
76
+ expect(FiniteNumber.max(a, c)).toBe(5.5);
77
+ });
78
+
79
+ test('floor, ceil, round', () => {
80
+ expect(FiniteNumber.floor(a)).toBe(5);
81
+ expect(FiniteNumber.ceil(a)).toBe(6);
82
+ expect(FiniteNumber.round(a)).toBe(6);
83
+ expect(FiniteNumber.floor(c)).toBe(-4);
84
+ expect(FiniteNumber.ceil(c)).toBe(-3);
85
+ expect(FiniteNumber.round(c)).toBe(-3);
86
+ });
87
+
88
+ test('add', () => {
89
+ expect(FiniteNumber.add(a, b)).toBe(8);
90
+ expect(FiniteNumber.add(a, c)).toBe(2);
91
+ });
92
+
93
+ test('sub', () => {
94
+ expect(FiniteNumber.sub(a, b)).toBe(3);
95
+ expect(FiniteNumber.sub(a, c)).toBe(9);
96
+ });
97
+
98
+ test('mul', () => {
99
+ expect(FiniteNumber.mul(a, b)).toBe(13.75);
100
+ expect(FiniteNumber.mul(a, c)).toBe(-19.25);
101
+ });
102
+
103
+ test('div', () => {
104
+ expect(FiniteNumber.div(a, asNonZeroFiniteNumber(2.5))).toBe(2.2);
105
+ expect(FiniteNumber.div(a, asNonZeroFiniteNumber(2))).toBe(2.75);
106
+ });
107
+
108
+ test('pow', () => {
109
+ expect(FiniteNumber.pow(asFiniteNumber(2), asFiniteNumber(3))).toBe(8);
110
+ expect(FiniteNumber.pow(asFiniteNumber(3), asFiniteNumber(2))).toBe(9);
111
+ });
112
+ });
113
+
114
+ describe('random', () => {
115
+ test('generates numbers within specified range', () => {
116
+ const min = asFiniteNumber(-5.5);
117
+ const max = asFiniteNumber(10.3);
118
+
119
+ for (let i = 0; i < 10; i++) {
120
+ const result = FiniteNumber.random(min, max);
121
+ expect(result).toBeGreaterThanOrEqual(min);
122
+ expect(result).toBeLessThanOrEqual(max);
123
+ expect(FiniteNumber.is(result)).toBe(true);
124
+ }
125
+ });
126
+ });
127
+
128
+ describe('type assertions', () => {
129
+ test('type relationships', () => {
130
+ expectType<FiniteNumber, number>('<=');
131
+
132
+ expectTypeOf(asFiniteNumber(5.5)).toExtend<FiniteNumber>();
133
+ });
134
+ });
135
+ });
@@ -0,0 +1,26 @@
1
+ export * from './finite-number.mjs';
2
+ export * from './int.mjs';
3
+ export * from './int16.mjs';
4
+ export * from './int32.mjs';
5
+ export * from './non-negative-finite-number.mjs';
6
+ export * from './non-negative-int16.mjs';
7
+ export * from './non-negative-int32.mjs';
8
+ export * from './non-zero-finite-number.mjs';
9
+ export * from './non-zero-int.mjs';
10
+ export * from './non-zero-int16.mjs';
11
+ export * from './non-zero-int32.mjs';
12
+ export * from './non-zero-safe-int.mjs';
13
+ export * from './non-zero-uint16.mjs';
14
+ export * from './non-zero-uint32.mjs';
15
+ export * from './positive-finite-number.mjs';
16
+ export * from './positive-int.mjs';
17
+ export * from './positive-int16.mjs';
18
+ export * from './positive-int32.mjs';
19
+ export * from './positive-safe-int.mjs';
20
+ export * from './positive-uint16.mjs';
21
+ export * from './positive-uint32.mjs';
22
+ export * from './safe-int.mjs';
23
+ export * from './safe-uint.mjs';
24
+ export * from './uint.mjs';
25
+ export * from './uint16.mjs';
26
+ export * from './uint32.mjs';