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.
- package/LICENSE +201 -0
- package/README.md +534 -0
- package/package.json +101 -0
- package/src/array/array-utils-creation.test.mts +443 -0
- package/src/array/array-utils-modification.test.mts +197 -0
- package/src/array/array-utils-overload-type-error.test.mts +149 -0
- package/src/array/array-utils-reducing-value.test.mts +425 -0
- package/src/array/array-utils-search.test.mts +169 -0
- package/src/array/array-utils-set-op.test.mts +335 -0
- package/src/array/array-utils-slice-clamped.test.mts +113 -0
- package/src/array/array-utils-slicing.test.mts +316 -0
- package/src/array/array-utils-transformation.test.mts +790 -0
- package/src/array/array-utils-validation.test.mts +492 -0
- package/src/array/array-utils.mts +4000 -0
- package/src/array/array.test.mts +146 -0
- package/src/array/index.mts +2 -0
- package/src/array/tuple-utils.mts +519 -0
- package/src/array/tuple-utils.test.mts +518 -0
- package/src/collections/imap-mapped.mts +801 -0
- package/src/collections/imap-mapped.test.mts +860 -0
- package/src/collections/imap.mts +651 -0
- package/src/collections/imap.test.mts +932 -0
- package/src/collections/index.mts +6 -0
- package/src/collections/iset-mapped.mts +889 -0
- package/src/collections/iset-mapped.test.mts +1187 -0
- package/src/collections/iset.mts +682 -0
- package/src/collections/iset.test.mts +1084 -0
- package/src/collections/queue.mts +390 -0
- package/src/collections/queue.test.mts +282 -0
- package/src/collections/stack.mts +423 -0
- package/src/collections/stack.test.mts +225 -0
- package/src/expect-type.mts +206 -0
- package/src/functional/index.mts +4 -0
- package/src/functional/match.mts +300 -0
- package/src/functional/match.test.mts +177 -0
- package/src/functional/optional.mts +733 -0
- package/src/functional/optional.test.mts +619 -0
- package/src/functional/pipe.mts +212 -0
- package/src/functional/pipe.test.mts +85 -0
- package/src/functional/result.mts +1134 -0
- package/src/functional/result.test.mts +777 -0
- package/src/globals.d.mts +38 -0
- package/src/guard/has-key.mts +119 -0
- package/src/guard/has-key.test.mts +219 -0
- package/src/guard/index.mts +7 -0
- package/src/guard/is-non-empty-string.mts +108 -0
- package/src/guard/is-non-empty-string.test.mts +91 -0
- package/src/guard/is-non-null-object.mts +106 -0
- package/src/guard/is-non-null-object.test.mts +90 -0
- package/src/guard/is-primitive.mts +165 -0
- package/src/guard/is-primitive.test.mts +102 -0
- package/src/guard/is-record.mts +153 -0
- package/src/guard/is-record.test.mts +112 -0
- package/src/guard/is-type.mts +450 -0
- package/src/guard/is-type.test.mts +496 -0
- package/src/guard/key-is-in.mts +163 -0
- package/src/guard/key-is-in.test.mts +19 -0
- package/src/index.mts +10 -0
- package/src/iterator/index.mts +1 -0
- package/src/iterator/range.mts +120 -0
- package/src/iterator/range.test.mts +33 -0
- package/src/json/index.mts +1 -0
- package/src/json/json.mts +711 -0
- package/src/json/json.test.mts +628 -0
- package/src/number/branded-types/finite-number.mts +354 -0
- package/src/number/branded-types/finite-number.test.mts +135 -0
- package/src/number/branded-types/index.mts +26 -0
- package/src/number/branded-types/int.mts +278 -0
- package/src/number/branded-types/int.test.mts +140 -0
- package/src/number/branded-types/int16.mts +192 -0
- package/src/number/branded-types/int16.test.mts +170 -0
- package/src/number/branded-types/int32.mts +193 -0
- package/src/number/branded-types/int32.test.mts +170 -0
- package/src/number/branded-types/non-negative-finite-number.mts +223 -0
- package/src/number/branded-types/non-negative-finite-number.test.mts +188 -0
- package/src/number/branded-types/non-negative-int16.mts +187 -0
- package/src/number/branded-types/non-negative-int16.test.mts +201 -0
- package/src/number/branded-types/non-negative-int32.mts +187 -0
- package/src/number/branded-types/non-negative-int32.test.mts +204 -0
- package/src/number/branded-types/non-zero-finite-number.mts +229 -0
- package/src/number/branded-types/non-zero-finite-number.test.mts +198 -0
- package/src/number/branded-types/non-zero-int.mts +167 -0
- package/src/number/branded-types/non-zero-int.test.mts +177 -0
- package/src/number/branded-types/non-zero-int16.mts +196 -0
- package/src/number/branded-types/non-zero-int16.test.mts +195 -0
- package/src/number/branded-types/non-zero-int32.mts +196 -0
- package/src/number/branded-types/non-zero-int32.test.mts +197 -0
- package/src/number/branded-types/non-zero-safe-int.mts +196 -0
- package/src/number/branded-types/non-zero-safe-int.test.mts +232 -0
- package/src/number/branded-types/non-zero-uint16.mts +189 -0
- package/src/number/branded-types/non-zero-uint16.test.mts +199 -0
- package/src/number/branded-types/non-zero-uint32.mts +189 -0
- package/src/number/branded-types/non-zero-uint32.test.mts +199 -0
- package/src/number/branded-types/positive-finite-number.mts +241 -0
- package/src/number/branded-types/positive-finite-number.test.mts +204 -0
- package/src/number/branded-types/positive-int.mts +304 -0
- package/src/number/branded-types/positive-int.test.mts +176 -0
- package/src/number/branded-types/positive-int16.mts +188 -0
- package/src/number/branded-types/positive-int16.test.mts +197 -0
- package/src/number/branded-types/positive-int32.mts +188 -0
- package/src/number/branded-types/positive-int32.test.mts +197 -0
- package/src/number/branded-types/positive-safe-int.mts +187 -0
- package/src/number/branded-types/positive-safe-int.test.mts +210 -0
- package/src/number/branded-types/positive-uint16.mts +188 -0
- package/src/number/branded-types/positive-uint16.test.mts +203 -0
- package/src/number/branded-types/positive-uint32.mts +188 -0
- package/src/number/branded-types/positive-uint32.test.mts +203 -0
- package/src/number/branded-types/safe-int.mts +291 -0
- package/src/number/branded-types/safe-int.test.mts +170 -0
- package/src/number/branded-types/safe-uint.mts +187 -0
- package/src/number/branded-types/safe-uint.test.mts +176 -0
- package/src/number/branded-types/uint.mts +179 -0
- package/src/number/branded-types/uint.test.mts +158 -0
- package/src/number/branded-types/uint16.mts +186 -0
- package/src/number/branded-types/uint16.test.mts +170 -0
- package/src/number/branded-types/uint32.mts +218 -0
- package/src/number/branded-types/uint32.test.mts +170 -0
- package/src/number/enum/index.mts +2 -0
- package/src/number/enum/int8.mts +344 -0
- package/src/number/enum/int8.test.mts +180 -0
- package/src/number/enum/uint8.mts +293 -0
- package/src/number/enum/uint8.test.mts +164 -0
- package/src/number/index.mts +4 -0
- package/src/number/num.mts +604 -0
- package/src/number/num.test.mts +242 -0
- package/src/number/refined-number-utils.mts +566 -0
- package/src/object/index.mts +1 -0
- package/src/object/object.mts +447 -0
- package/src/object/object.test.mts +124 -0
- package/src/others/cast-mutable.mts +113 -0
- package/src/others/cast-readonly.mts +192 -0
- package/src/others/cast-readonly.test.mts +89 -0
- package/src/others/if-then.mts +98 -0
- package/src/others/if-then.test.mts +75 -0
- package/src/others/index.mts +7 -0
- package/src/others/map-nullable.mts +172 -0
- package/src/others/map-nullable.test.mts +297 -0
- package/src/others/memoize-function.mts +196 -0
- package/src/others/memoize-function.test.mts +168 -0
- package/src/others/tuple.mts +160 -0
- package/src/others/tuple.test.mts +11 -0
- package/src/others/unknown-to-string.mts +215 -0
- package/src/others/unknown-to-string.test.mts +114 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import { TsVerifiedInternals } from '../refined-number-utils.mjs';
|
|
3
|
+
|
|
4
|
+
type ElementType = Int;
|
|
5
|
+
|
|
6
|
+
const typeNameInMessage = 'an integer';
|
|
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.operatorsForInteger<
|
|
21
|
+
ElementType,
|
|
22
|
+
undefined,
|
|
23
|
+
undefined
|
|
24
|
+
>({
|
|
25
|
+
integerOrSafeInteger: 'Integer',
|
|
26
|
+
MIN_VALUE: undefined,
|
|
27
|
+
MAX_VALUE: undefined,
|
|
28
|
+
typeNameInMessage,
|
|
29
|
+
} as const);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Type guard that checks if a value is an integer.
|
|
33
|
+
*
|
|
34
|
+
* Returns `true` if the value is any integer (positive, negative, or zero),
|
|
35
|
+
* with no fractional component. This includes values outside the safe integer
|
|
36
|
+
* range, unlike SafeInt.
|
|
37
|
+
*
|
|
38
|
+
* @param value - The value to check
|
|
39
|
+
* @returns `true` if the value is an integer, `false` otherwise
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* isInt(5); // true
|
|
44
|
+
* isInt(-10); // true
|
|
45
|
+
* isInt(0); // true
|
|
46
|
+
* isInt(5.5); // false
|
|
47
|
+
* isInt(NaN); // false
|
|
48
|
+
* isInt(Infinity); // false
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export const isInt = is;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Casts a number to an Int branded type.
|
|
55
|
+
*
|
|
56
|
+
* This function validates that the input is an integer and returns it with
|
|
57
|
+
* the Int brand. Throws a TypeError if the value has a fractional component
|
|
58
|
+
* or is not a finite number.
|
|
59
|
+
*
|
|
60
|
+
* @param value - The value to cast
|
|
61
|
+
* @returns The value as an Int branded type
|
|
62
|
+
* @throws {TypeError} If the value is not an integer
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const x = asInt(5); // Int
|
|
67
|
+
* const y = asInt(-10); // Int
|
|
68
|
+
* const z = asInt(0); // Int
|
|
69
|
+
*
|
|
70
|
+
* // These throw TypeError:
|
|
71
|
+
* // asInt(5.5); // Not an integer
|
|
72
|
+
* // asInt(NaN); // Not a number
|
|
73
|
+
* // asInt(Infinity); // Not finite
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export const asInt = castType;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Namespace providing type-safe operations for Int branded types.
|
|
80
|
+
*
|
|
81
|
+
* The Int type represents any integer value (no fractional component) without
|
|
82
|
+
* range restrictions. All operations preserve the integer constraint, using
|
|
83
|
+
* floor division for division operations.
|
|
84
|
+
*
|
|
85
|
+
* Unlike SafeInt, Int allows values outside the safe integer range
|
|
86
|
+
* (±2^53 - 1), but be aware that very large integers may lose precision
|
|
87
|
+
* in JavaScript's number type.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* // Type validation
|
|
92
|
+
* Int.is(42); // true
|
|
93
|
+
* Int.is(3.14); // false
|
|
94
|
+
* Int.is(-0); // true (negative zero is an integer)
|
|
95
|
+
*
|
|
96
|
+
* // Basic arithmetic
|
|
97
|
+
* const a = asInt(10);
|
|
98
|
+
* const b = asInt(3);
|
|
99
|
+
*
|
|
100
|
+
* const sum = Int.add(a, b); // Int (13)
|
|
101
|
+
* const diff = Int.sub(a, b); // Int (7)
|
|
102
|
+
* const product = Int.mul(a, b); // Int (30)
|
|
103
|
+
* const quotient = Int.div(a, b); // Int (3) - floor division
|
|
104
|
+
* const power = Int.pow(a, b); // Int (1000)
|
|
105
|
+
*
|
|
106
|
+
* // Utility operations
|
|
107
|
+
* const absolute = Int.abs(asInt(-42)); // Int (42)
|
|
108
|
+
* const minimum = Int.min(a, b, asInt(5)); // Int (3)
|
|
109
|
+
* const maximum = Int.max(a, b, asInt(5)); // Int (10)
|
|
110
|
+
*
|
|
111
|
+
* // Random generation
|
|
112
|
+
* const die = Int.random(asInt(1), asInt(6)); // Random Int in [1, 6]
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export const Int = {
|
|
116
|
+
/**
|
|
117
|
+
* Type guard that checks if a value is an integer.
|
|
118
|
+
*
|
|
119
|
+
* @param value - The value to check
|
|
120
|
+
* @returns `true` if the value is an integer, `false` otherwise
|
|
121
|
+
*
|
|
122
|
+
* @see {@link isInt} for usage examples
|
|
123
|
+
*/
|
|
124
|
+
is,
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Returns the absolute value of an integer.
|
|
128
|
+
*
|
|
129
|
+
* The result is always non-negative and maintains the Int brand.
|
|
130
|
+
* Note that Math.abs(Number.MIN_SAFE_INTEGER) exceeds Number.MAX_SAFE_INTEGER,
|
|
131
|
+
* so use SafeInt for guaranteed precision.
|
|
132
|
+
*
|
|
133
|
+
* @param a - The integer value
|
|
134
|
+
* @returns The absolute value as a non-negative Int
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* Int.abs(asInt(-5)); // Int (5)
|
|
139
|
+
* Int.abs(asInt(3)); // Int (3)
|
|
140
|
+
* Int.abs(asInt(-0)); // Int (0)
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
abs,
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Returns the minimum value from a list of integers.
|
|
147
|
+
*
|
|
148
|
+
* @param values - The integers to compare (at least one required)
|
|
149
|
+
* @returns The smallest value as an Int
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* Int.min(asInt(5), asInt(3)); // Int (3)
|
|
154
|
+
* Int.min(asInt(-10), asInt(0), asInt(10)); // Int (-10)
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
min: min_,
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Returns the maximum value from a list of integers.
|
|
161
|
+
*
|
|
162
|
+
* @param values - The integers to compare (at least one required)
|
|
163
|
+
* @returns The largest value as an Int
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* Int.max(asInt(5), asInt(3)); // Int (5)
|
|
168
|
+
* Int.max(asInt(-10), asInt(0), asInt(10)); // Int (10)
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
max: max_,
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Generates a random integer within the specified range (inclusive).
|
|
175
|
+
*
|
|
176
|
+
* The range is inclusive on both ends, so random(1, 6) can return
|
|
177
|
+
* any of: 1, 2, 3, 4, 5, or 6.
|
|
178
|
+
*
|
|
179
|
+
* @param min - The minimum value (inclusive)
|
|
180
|
+
* @param max - The maximum value (inclusive)
|
|
181
|
+
* @returns A random Int in the range [min, max]
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* // Dice roll
|
|
186
|
+
* const d6 = Int.random(asInt(1), asInt(6));
|
|
187
|
+
*
|
|
188
|
+
* // Random array index
|
|
189
|
+
* const index = Int.random(asInt(0), asInt(array.length - 1));
|
|
190
|
+
*
|
|
191
|
+
* // Can generate negative values
|
|
192
|
+
* const temp = Int.random(asInt(-10), asInt(10));
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
random,
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Raises an integer to a power.
|
|
199
|
+
* @param a - The base integer
|
|
200
|
+
* @param b - The exponent integer
|
|
201
|
+
* @returns `a ** b` as an Int
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* Int.pow(asInt(2), asInt(3)); // Int (8)
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
pow,
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Adds two integers.
|
|
211
|
+
* @param a - First integer
|
|
212
|
+
* @param b - Second integer
|
|
213
|
+
* @returns `a + b` as an Int
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* Int.add(asInt(5), asInt(3)); // Int (8)
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
add,
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Subtracts two integers.
|
|
223
|
+
* @param a - First integer
|
|
224
|
+
* @param b - Second integer
|
|
225
|
+
* @returns `a - b` as an Int
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* Int.sub(asInt(8), asInt(3)); // Int (5)
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
sub,
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Multiplies two integers.
|
|
235
|
+
* @param a - First integer
|
|
236
|
+
* @param b - Second integer
|
|
237
|
+
* @returns `a * b` as an Int
|
|
238
|
+
* @example
|
|
239
|
+
* ```typescript
|
|
240
|
+
* Int.mul(asInt(4), asInt(3)); // Int (12)
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
mul,
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Divides two integers using floor division.
|
|
247
|
+
*
|
|
248
|
+
* Performs mathematical floor division: `⌊a / b⌋`.
|
|
249
|
+
* The result is always an integer, rounding toward negative infinity.
|
|
250
|
+
*
|
|
251
|
+
* @param a - The dividend
|
|
252
|
+
* @param b - The divisor (must be non-zero)
|
|
253
|
+
* @returns The integer quotient as an Int
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```typescript
|
|
257
|
+
* // Positive division
|
|
258
|
+
* Int.div(asInt(10), asInt(3)); // Int (3)
|
|
259
|
+
* Int.div(asInt(9), asInt(3)); // Int (3)
|
|
260
|
+
*
|
|
261
|
+
* // Negative division (rounds toward -∞)
|
|
262
|
+
* Int.div(asInt(-10), asInt(3)); // Int (-4)
|
|
263
|
+
* Int.div(asInt(10), asInt(-3)); // Int (-4)
|
|
264
|
+
* Int.div(asInt(-10), asInt(-3)); // Int (3)
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
div,
|
|
268
|
+
} as const;
|
|
269
|
+
|
|
270
|
+
expectType<
|
|
271
|
+
keyof typeof Int,
|
|
272
|
+
keyof TsVerifiedInternals.RefinedNumberUtils.NumberClass<ElementType, 'int'>
|
|
273
|
+
>('=');
|
|
274
|
+
|
|
275
|
+
expectType<
|
|
276
|
+
typeof Int,
|
|
277
|
+
TsVerifiedInternals.RefinedNumberUtils.NumberClass<ElementType, 'int'>
|
|
278
|
+
>('<=');
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import { asInt, Int, isInt } from './int.mjs';
|
|
3
|
+
import { asNonZeroInt } from './non-zero-int.mjs';
|
|
4
|
+
|
|
5
|
+
describe('Int', () => {
|
|
6
|
+
describe('asInt', () => {
|
|
7
|
+
test('accepts valid integers', () => {
|
|
8
|
+
expect(() => asInt(0)).not.toThrow();
|
|
9
|
+
expect(() => asInt(1)).not.toThrow();
|
|
10
|
+
expect(() => asInt(-1)).not.toThrow();
|
|
11
|
+
expect(() => asInt(42)).not.toThrow();
|
|
12
|
+
expect(() => asInt(-42)).not.toThrow();
|
|
13
|
+
expect(() => asInt(Number.MAX_SAFE_INTEGER)).not.toThrow();
|
|
14
|
+
expect(() => asInt(Number.MIN_SAFE_INTEGER)).not.toThrow();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('rejects non-integers', () => {
|
|
18
|
+
expect(() => asInt(Number.NaN)).toThrow(TypeError);
|
|
19
|
+
expect(() => asInt(Number.POSITIVE_INFINITY)).toThrow(TypeError);
|
|
20
|
+
expect(() => asInt(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
|
|
21
|
+
expect(() => asInt(1.2)).toThrow(TypeError);
|
|
22
|
+
expect(() => asInt(-3.4)).toThrow(TypeError);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('returns the same value for valid inputs', () => {
|
|
26
|
+
expect(asInt(5)).toBe(5);
|
|
27
|
+
expect(asInt(-10)).toBe(-10);
|
|
28
|
+
expect(asInt(0)).toBe(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test.each([
|
|
32
|
+
{ name: 'Number.NaN', value: Number.NaN },
|
|
33
|
+
{ name: 'Number.POSITIVE_INFINITY', value: Number.POSITIVE_INFINITY },
|
|
34
|
+
{ name: 'Number.NEGATIVE_INFINITY', value: Number.NEGATIVE_INFINITY },
|
|
35
|
+
{ name: '1.2', value: 1.2 },
|
|
36
|
+
{ name: '-3.4', value: -3.4 },
|
|
37
|
+
] as const)(`asInt($name) should throw a TypeError`, ({ value }) => {
|
|
38
|
+
expect(() => asInt(value)).toThrow(
|
|
39
|
+
new TypeError(`Expected an integer, got: ${value}`),
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('isInt', () => {
|
|
45
|
+
test('correctly identifies integers', () => {
|
|
46
|
+
expect(isInt(0)).toBe(true);
|
|
47
|
+
expect(isInt(1)).toBe(true);
|
|
48
|
+
expect(isInt(-1)).toBe(true);
|
|
49
|
+
expect(isInt(42)).toBe(true);
|
|
50
|
+
expect(isInt(-42)).toBe(true);
|
|
51
|
+
expect(isInt(Number.MAX_SAFE_INTEGER)).toBe(true);
|
|
52
|
+
expect(isInt(Number.MIN_SAFE_INTEGER)).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('correctly identifies non-integers', () => {
|
|
56
|
+
expect(isInt(Number.NaN)).toBe(false);
|
|
57
|
+
expect(isInt(Number.POSITIVE_INFINITY)).toBe(false);
|
|
58
|
+
expect(isInt(Number.NEGATIVE_INFINITY)).toBe(false);
|
|
59
|
+
expect(isInt(1.2)).toBe(false);
|
|
60
|
+
expect(isInt(-3.4)).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('Int.is', () => {
|
|
65
|
+
test('same as isInt function', () => {
|
|
66
|
+
expect(Int.is(5)).toBe(isInt(5));
|
|
67
|
+
expect(Int.is(1.5)).toBe(isInt(1.5));
|
|
68
|
+
expect(Int.is(-10)).toBe(isInt(-10));
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('mathematical operations', () => {
|
|
73
|
+
const a = asInt(5);
|
|
74
|
+
const b = asInt(2);
|
|
75
|
+
const c = asInt(-3);
|
|
76
|
+
|
|
77
|
+
test('abs', () => {
|
|
78
|
+
expect(Int.abs(a)).toBe(5);
|
|
79
|
+
expect(Int.abs(c)).toBe(3);
|
|
80
|
+
expect(Int.abs(asInt(0))).toBe(0);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('min and max', () => {
|
|
84
|
+
expect(Int.min(a, b)).toBe(2);
|
|
85
|
+
expect(Int.max(a, b)).toBe(5);
|
|
86
|
+
expect(Int.min(a, c)).toBe(-3);
|
|
87
|
+
expect(Int.max(a, c)).toBe(5);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('add', () => {
|
|
91
|
+
expect(Int.add(a, b)).toBe(7);
|
|
92
|
+
expect(Int.add(a, c)).toBe(2);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('sub', () => {
|
|
96
|
+
expect(Int.sub(a, b)).toBe(3);
|
|
97
|
+
expect(Int.sub(a, c)).toBe(8);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('mul', () => {
|
|
101
|
+
expect(Int.mul(a, b)).toBe(10);
|
|
102
|
+
expect(Int.mul(a, c)).toBe(-15);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('div (floor division)', () => {
|
|
106
|
+
expect(Int.div(a, asNonZeroInt(2))).toBe(2);
|
|
107
|
+
expect(Int.div(asInt(7), asNonZeroInt(3))).toBe(2);
|
|
108
|
+
expect(Int.div(asInt(-7), asNonZeroInt(3))).toBe(-3);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('pow', () => {
|
|
112
|
+
expect(Int.pow(asInt(2), asInt(3))).toBe(8);
|
|
113
|
+
expect(Int.pow(asInt(3), asInt(2))).toBe(9);
|
|
114
|
+
expect(Int.pow(asInt(-2), asInt(3))).toBe(-8);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('random', () => {
|
|
119
|
+
test('generates integers within specified range', () => {
|
|
120
|
+
const min = -5;
|
|
121
|
+
const max = 10;
|
|
122
|
+
|
|
123
|
+
for (let i = 0; i < 10; i++) {
|
|
124
|
+
const result = Int.random(min, max);
|
|
125
|
+
expect(result).toBeGreaterThanOrEqual(min);
|
|
126
|
+
expect(result).toBeLessThanOrEqual(max);
|
|
127
|
+
expect(Int.is(result)).toBe(true);
|
|
128
|
+
expect(Number.isInteger(result)).toBe(true);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe('type assertions', () => {
|
|
134
|
+
test('type relationships', () => {
|
|
135
|
+
expectType<Int, number>('<=');
|
|
136
|
+
|
|
137
|
+
expectTypeOf(asInt(5)).toExtend<Int>();
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import { TsVerifiedInternals } from '../refined-number-utils.mjs';
|
|
3
|
+
|
|
4
|
+
type ElementType = Int16;
|
|
5
|
+
|
|
6
|
+
const typeNameInMessage = 'an integer in [-2^15, 2^15)';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
MIN_VALUE,
|
|
10
|
+
MAX_VALUE,
|
|
11
|
+
min: min_,
|
|
12
|
+
max: max_,
|
|
13
|
+
abs,
|
|
14
|
+
pow,
|
|
15
|
+
add,
|
|
16
|
+
sub,
|
|
17
|
+
mul,
|
|
18
|
+
div,
|
|
19
|
+
random,
|
|
20
|
+
is,
|
|
21
|
+
castType,
|
|
22
|
+
clamp,
|
|
23
|
+
} = TsVerifiedInternals.RefinedNumberUtils.operatorsForInteger<
|
|
24
|
+
ElementType,
|
|
25
|
+
number,
|
|
26
|
+
number
|
|
27
|
+
>({
|
|
28
|
+
integerOrSafeInteger: 'SafeInteger',
|
|
29
|
+
MIN_VALUE: -(2 ** 15),
|
|
30
|
+
MAX_VALUE: 2 ** 15 - 1,
|
|
31
|
+
typeNameInMessage,
|
|
32
|
+
} as const);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a number is an Int16 (16-bit signed integer in the range [-2^15, 2^15)).
|
|
36
|
+
* @param value The value to check.
|
|
37
|
+
* @returns `true` if the value is an Int16, `false` otherwise.
|
|
38
|
+
*/
|
|
39
|
+
export const isInt16 = is;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Casts a number to an Int16 type.
|
|
43
|
+
* @param value The value to cast.
|
|
44
|
+
* @returns The value as an Int16 type.
|
|
45
|
+
* @throws {TypeError} If the value is not an integer in [-2^15, 2^15).
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const x = asInt16(1000); // Int16
|
|
49
|
+
* const y = asInt16(-5000); // Int16
|
|
50
|
+
* // asInt16(50000); // throws TypeError
|
|
51
|
+
* // asInt16(1.5); // throws TypeError
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export const asInt16 = castType;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Namespace providing type-safe arithmetic operations for 16-bit signed integers.
|
|
58
|
+
*
|
|
59
|
+
* All operations automatically clamp results to the valid Int16 range [-32768, 32767].
|
|
60
|
+
* This ensures that all arithmetic maintains the 16-bit signed integer constraint.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const a = asInt16(30000);
|
|
65
|
+
* const b = asInt16(5000);
|
|
66
|
+
*
|
|
67
|
+
* // Arithmetic operations with automatic clamping
|
|
68
|
+
* const sum = Int16.add(a, b); // Int16 (32767 - clamped to MAX_VALUE)
|
|
69
|
+
* const diff = Int16.sub(a, b); // Int16 (25000)
|
|
70
|
+
* const product = Int16.mul(a, b); // Int16 (32767 - clamped due to overflow)
|
|
71
|
+
*
|
|
72
|
+
* // Range operations
|
|
73
|
+
* const clamped = Int16.clamp(100000); // Int16 (32767)
|
|
74
|
+
* const minimum = Int16.min(a, b); // Int16 (5000)
|
|
75
|
+
* const maximum = Int16.max(a, b); // Int16 (30000)
|
|
76
|
+
*
|
|
77
|
+
* // Range constants
|
|
78
|
+
* const range = Int16.MAX_VALUE - Int16.MIN_VALUE + 1; // 65536
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export const Int16 = {
|
|
82
|
+
/**
|
|
83
|
+
* Type guard to check if a value is an Int16.
|
|
84
|
+
* @param value The value to check.
|
|
85
|
+
* @returns `true` if the value is a 16-bit signed integer, `false` otherwise.
|
|
86
|
+
*/
|
|
87
|
+
is,
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The minimum value for a 16-bit signed integer.
|
|
91
|
+
* @readonly
|
|
92
|
+
*/
|
|
93
|
+
MIN_VALUE,
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The maximum value for a 16-bit signed integer.
|
|
97
|
+
* @readonly
|
|
98
|
+
*/
|
|
99
|
+
MAX_VALUE,
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Returns the absolute value of a 16-bit signed integer.
|
|
103
|
+
* @param a The Int16 value.
|
|
104
|
+
* @returns The absolute value as an Int16, clamped to valid range.
|
|
105
|
+
*/
|
|
106
|
+
abs,
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Returns the smaller of two Int16 values.
|
|
110
|
+
* @param a The first Int16.
|
|
111
|
+
* @param b The second Int16.
|
|
112
|
+
* @returns The minimum value as an Int16.
|
|
113
|
+
*/
|
|
114
|
+
min: min_,
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Returns the larger of two Int16 values.
|
|
118
|
+
* @param a The first Int16.
|
|
119
|
+
* @param b The second Int16.
|
|
120
|
+
* @returns The maximum value as an Int16.
|
|
121
|
+
*/
|
|
122
|
+
max: max_,
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Clamps a number to the Int16 range.
|
|
126
|
+
* @param value The number to clamp.
|
|
127
|
+
* @returns The value clamped to [-32768, 32767] as an Int16.
|
|
128
|
+
*/
|
|
129
|
+
clamp,
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Generates a random Int16 value within the valid range.
|
|
133
|
+
* @returns A random Int16 between MIN_VALUE and MAX_VALUE.
|
|
134
|
+
*/
|
|
135
|
+
random,
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Raises an Int16 to the power of another Int16.
|
|
139
|
+
* @param a The base Int16.
|
|
140
|
+
* @param b The exponent Int16.
|
|
141
|
+
* @returns `a ** b` clamped to [-32768, 32767] as an Int16.
|
|
142
|
+
*/
|
|
143
|
+
pow,
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Adds two Int16 values.
|
|
147
|
+
* @param a The first Int16.
|
|
148
|
+
* @param b The second Int16.
|
|
149
|
+
* @returns `a + b` clamped to [-32768, 32767] as an Int16.
|
|
150
|
+
*/
|
|
151
|
+
add,
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Subtracts one Int16 from another.
|
|
155
|
+
* @param a The minuend Int16.
|
|
156
|
+
* @param b The subtrahend Int16.
|
|
157
|
+
* @returns `a - b` clamped to [-32768, 32767] as an Int16.
|
|
158
|
+
*/
|
|
159
|
+
sub,
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Multiplies two Int16 values.
|
|
163
|
+
* @param a The first Int16.
|
|
164
|
+
* @param b The second Int16.
|
|
165
|
+
* @returns `a * b` clamped to [-32768, 32767] as an Int16.
|
|
166
|
+
*/
|
|
167
|
+
mul,
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Divides one Int16 by another using floor division.
|
|
171
|
+
* @param a The dividend Int16.
|
|
172
|
+
* @param b The divisor Int16.
|
|
173
|
+
* @returns `⌊a / b⌋` clamped to [-32768, 32767] as an Int16.
|
|
174
|
+
*/
|
|
175
|
+
div,
|
|
176
|
+
} as const;
|
|
177
|
+
|
|
178
|
+
expectType<
|
|
179
|
+
keyof typeof Int16,
|
|
180
|
+
keyof TsVerifiedInternals.RefinedNumberUtils.NumberClass<
|
|
181
|
+
ElementType,
|
|
182
|
+
'int' | 'range'
|
|
183
|
+
>
|
|
184
|
+
>('=');
|
|
185
|
+
|
|
186
|
+
expectType<
|
|
187
|
+
typeof Int16,
|
|
188
|
+
TsVerifiedInternals.RefinedNumberUtils.NumberClass<
|
|
189
|
+
ElementType,
|
|
190
|
+
'int' | 'range'
|
|
191
|
+
>
|
|
192
|
+
>('<=');
|