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,229 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import { TsVerifiedInternals } from '../refined-number-utils.mjs';
|
|
3
|
+
|
|
4
|
+
type ElementType = NonZeroFiniteNumber;
|
|
5
|
+
|
|
6
|
+
const typeNameInMessage = 'a non-zero finite number';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
abs,
|
|
10
|
+
min: min_,
|
|
11
|
+
max: max_,
|
|
12
|
+
pow,
|
|
13
|
+
add,
|
|
14
|
+
sub,
|
|
15
|
+
mul,
|
|
16
|
+
div,
|
|
17
|
+
randomNonZero: random,
|
|
18
|
+
is,
|
|
19
|
+
castType,
|
|
20
|
+
} = TsVerifiedInternals.RefinedNumberUtils.operatorsForFloat<
|
|
21
|
+
ElementType,
|
|
22
|
+
undefined,
|
|
23
|
+
undefined
|
|
24
|
+
>({
|
|
25
|
+
nonZero: true,
|
|
26
|
+
MIN_VALUE: undefined,
|
|
27
|
+
MAX_VALUE: undefined,
|
|
28
|
+
typeNameInMessage,
|
|
29
|
+
} as const);
|
|
30
|
+
|
|
31
|
+
// Not provided because reasonable rounding operations that avoid becoming 0 cannot be defined
|
|
32
|
+
|
|
33
|
+
const floor = (
|
|
34
|
+
x: ElementType,
|
|
35
|
+
): TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType> =>
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
37
|
+
Math.floor(x) as TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>;
|
|
38
|
+
|
|
39
|
+
const ceil = (
|
|
40
|
+
x: ElementType,
|
|
41
|
+
): TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType> =>
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
43
|
+
Math.ceil(x) as TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>;
|
|
44
|
+
|
|
45
|
+
const round = (
|
|
46
|
+
x: ElementType,
|
|
47
|
+
): TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType> =>
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
49
|
+
Math.round(x) as TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>;
|
|
50
|
+
|
|
51
|
+
expectType<
|
|
52
|
+
TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>,
|
|
53
|
+
NonZeroInt
|
|
54
|
+
>('=');
|
|
55
|
+
|
|
56
|
+
expectType<
|
|
57
|
+
TsVerifiedInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
58
|
+
TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
59
|
+
>,
|
|
60
|
+
Int
|
|
61
|
+
>('=');
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Checks if a number is a NonZeroFiniteNumber (a finite number that is not 0).
|
|
65
|
+
* @param value The value to check.
|
|
66
|
+
* @returns `true` if the value is a NonZeroFiniteNumber, `false` otherwise.
|
|
67
|
+
*/
|
|
68
|
+
export const isNonZeroFiniteNumber = is;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Casts a number to a NonZeroFiniteNumber type.
|
|
72
|
+
* @param value The value to cast.
|
|
73
|
+
* @returns The value as a NonZeroFiniteNumber type.
|
|
74
|
+
* @throws {TypeError} If the value is not a non-zero finite number.
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const x = asNonZeroFiniteNumber(5.5); // NonZeroFiniteNumber
|
|
78
|
+
* const y = asNonZeroFiniteNumber(-3.2); // NonZeroFiniteNumber
|
|
79
|
+
* // asNonZeroFiniteNumber(0); // throws TypeError
|
|
80
|
+
* // asNonZeroFiniteNumber(Infinity); // throws TypeError
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export const asNonZeroFiniteNumber = castType;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Namespace providing type-safe arithmetic operations for non-zero finite numbers.
|
|
87
|
+
*
|
|
88
|
+
* All operations maintain the non-zero constraint while ensuring results remain finite
|
|
89
|
+
* (excluding NaN and Infinity). This type is useful for values that must never be zero,
|
|
90
|
+
* such as denominators, scaling factors, and ratios.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* const factor = asNonZeroFiniteNumber(2.5);
|
|
95
|
+
* const multiplier = asNonZeroFiniteNumber(-1.5);
|
|
96
|
+
*
|
|
97
|
+
* // Arithmetic operations that preserve non-zero constraint
|
|
98
|
+
* const result = NonZeroFiniteNumber.add(factor, multiplier); // NonZeroFiniteNumber (1.0)
|
|
99
|
+
* const difference = NonZeroFiniteNumber.sub(factor, multiplier); // NonZeroFiniteNumber (4.0)
|
|
100
|
+
* const product = NonZeroFiniteNumber.mul(factor, multiplier); // NonZeroFiniteNumber (-3.75)
|
|
101
|
+
* const quotient = NonZeroFiniteNumber.div(factor, multiplier); // NonZeroFiniteNumber (-1.666...)
|
|
102
|
+
*
|
|
103
|
+
* // Utility operations
|
|
104
|
+
* const absolute = NonZeroFiniteNumber.abs(multiplier); // NonZeroFiniteNumber (1.5)
|
|
105
|
+
* const minimum = NonZeroFiniteNumber.min(factor, multiplier); // NonZeroFiniteNumber (-1.5)
|
|
106
|
+
* const maximum = NonZeroFiniteNumber.max(factor, multiplier); // NonZeroFiniteNumber (2.5)
|
|
107
|
+
*
|
|
108
|
+
* // Rounding operations (return NonZeroInt)
|
|
109
|
+
* const rounded = NonZeroFiniteNumber.round(factor); // NonZeroInt (3)
|
|
110
|
+
* const floored = NonZeroFiniteNumber.floor(factor); // NonZeroInt (2)
|
|
111
|
+
* const ceiled = NonZeroFiniteNumber.ceil(factor); // NonZeroInt (3)
|
|
112
|
+
*
|
|
113
|
+
* // Random generation
|
|
114
|
+
* const randomValue = NonZeroFiniteNumber.random(); // NonZeroFiniteNumber (random non-zero value)
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export const NonZeroFiniteNumber = {
|
|
118
|
+
/**
|
|
119
|
+
* Type guard to check if a value is a NonZeroFiniteNumber.
|
|
120
|
+
* @param value The value to check.
|
|
121
|
+
* @returns `true` if the value is a non-zero finite number, `false` otherwise.
|
|
122
|
+
*/
|
|
123
|
+
is,
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Returns the absolute value of a non-zero finite number.
|
|
127
|
+
* @param a The NonZeroFiniteNumber.
|
|
128
|
+
* @returns The absolute value as a NonZeroFiniteNumber.
|
|
129
|
+
*/
|
|
130
|
+
abs,
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Returns the smaller of two NonZeroFiniteNumber values.
|
|
134
|
+
* @param a The first NonZeroFiniteNumber.
|
|
135
|
+
* @param b The second NonZeroFiniteNumber.
|
|
136
|
+
* @returns The minimum value as a NonZeroFiniteNumber.
|
|
137
|
+
*/
|
|
138
|
+
min: min_,
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Returns the larger of two NonZeroFiniteNumber values.
|
|
142
|
+
* @param a The first NonZeroFiniteNumber.
|
|
143
|
+
* @param b The second NonZeroFiniteNumber.
|
|
144
|
+
* @returns The maximum value as a NonZeroFiniteNumber.
|
|
145
|
+
*/
|
|
146
|
+
max: max_,
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Rounds down a NonZeroFiniteNumber to the nearest integer.
|
|
150
|
+
* @param x The NonZeroFiniteNumber to round down.
|
|
151
|
+
* @returns The floor value as a NonZeroInt.
|
|
152
|
+
*/
|
|
153
|
+
floor,
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Rounds up a NonZeroFiniteNumber to the nearest integer.
|
|
157
|
+
* @param x The NonZeroFiniteNumber to round up.
|
|
158
|
+
* @returns The ceiling value as a NonZeroInt.
|
|
159
|
+
*/
|
|
160
|
+
ceil,
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Rounds a NonZeroFiniteNumber to the nearest integer.
|
|
164
|
+
* @param x The NonZeroFiniteNumber to round.
|
|
165
|
+
* @returns The rounded value as a NonZeroInt.
|
|
166
|
+
*/
|
|
167
|
+
round,
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Generates a random NonZeroFiniteNumber value.
|
|
171
|
+
* @returns A random non-zero finite number.
|
|
172
|
+
*/
|
|
173
|
+
random,
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Raises a NonZeroFiniteNumber to the power of another NonZeroFiniteNumber.
|
|
177
|
+
* @param a The base NonZeroFiniteNumber.
|
|
178
|
+
* @param b The exponent NonZeroFiniteNumber.
|
|
179
|
+
* @returns `a ** b` as a NonZeroFiniteNumber.
|
|
180
|
+
*/
|
|
181
|
+
pow,
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Adds two NonZeroFiniteNumber values.
|
|
185
|
+
* @param a The first NonZeroFiniteNumber.
|
|
186
|
+
* @param b The second NonZeroFiniteNumber.
|
|
187
|
+
* @returns `a + b` as a NonZeroFiniteNumber.
|
|
188
|
+
*/
|
|
189
|
+
add,
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Subtracts one NonZeroFiniteNumber from another.
|
|
193
|
+
* @param a The minuend NonZeroFiniteNumber.
|
|
194
|
+
* @param b The subtrahend NonZeroFiniteNumber.
|
|
195
|
+
* @returns `a - b` as a NonZeroFiniteNumber.
|
|
196
|
+
*/
|
|
197
|
+
sub,
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Multiplies two NonZeroFiniteNumber values.
|
|
201
|
+
* @param a The first NonZeroFiniteNumber.
|
|
202
|
+
* @param b The second NonZeroFiniteNumber.
|
|
203
|
+
* @returns `a * b` as a NonZeroFiniteNumber.
|
|
204
|
+
*/
|
|
205
|
+
mul,
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Divides one NonZeroFiniteNumber by another.
|
|
209
|
+
* @param a The dividend NonZeroFiniteNumber.
|
|
210
|
+
* @param b The divisor NonZeroFiniteNumber.
|
|
211
|
+
* @returns `a / b` as a NonZeroFiniteNumber.
|
|
212
|
+
*/
|
|
213
|
+
div,
|
|
214
|
+
} as const;
|
|
215
|
+
|
|
216
|
+
expectType<
|
|
217
|
+
TsVerifiedInternals.RefinedNumberUtils.ToNonNegative<ElementType>,
|
|
218
|
+
PositiveFiniteNumber
|
|
219
|
+
>('=');
|
|
220
|
+
|
|
221
|
+
expectType<
|
|
222
|
+
keyof typeof NonZeroFiniteNumber,
|
|
223
|
+
keyof TsVerifiedInternals.RefinedNumberUtils.NumberClass<ElementType, never>
|
|
224
|
+
>('=');
|
|
225
|
+
|
|
226
|
+
expectType<
|
|
227
|
+
typeof NonZeroFiniteNumber,
|
|
228
|
+
TsVerifiedInternals.RefinedNumberUtils.NumberClass<ElementType, never>
|
|
229
|
+
>('<=');
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import {
|
|
3
|
+
asNonZeroFiniteNumber,
|
|
4
|
+
isNonZeroFiniteNumber,
|
|
5
|
+
NonZeroFiniteNumber,
|
|
6
|
+
} from './non-zero-finite-number.mjs';
|
|
7
|
+
|
|
8
|
+
describe('NonZeroFiniteNumber', () => {
|
|
9
|
+
describe('asNonZeroFiniteNumber', () => {
|
|
10
|
+
test('accepts valid non-zero finite numbers', () => {
|
|
11
|
+
expect(() => asNonZeroFiniteNumber(1)).not.toThrow();
|
|
12
|
+
expect(() => asNonZeroFiniteNumber(-1)).not.toThrow();
|
|
13
|
+
expect(() => asNonZeroFiniteNumber(3.14)).not.toThrow();
|
|
14
|
+
expect(() => asNonZeroFiniteNumber(-2.5)).not.toThrow();
|
|
15
|
+
expect(() => asNonZeroFiniteNumber(0.001)).not.toThrow();
|
|
16
|
+
expect(() => asNonZeroFiniteNumber(-0.001)).not.toThrow();
|
|
17
|
+
expect(() => asNonZeroFiniteNumber(Number.MAX_VALUE)).not.toThrow();
|
|
18
|
+
expect(() => asNonZeroFiniteNumber(-Number.MAX_VALUE)).not.toThrow();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('rejects zero', () => {
|
|
22
|
+
expect(() => asNonZeroFiniteNumber(0)).toThrow(TypeError);
|
|
23
|
+
expect(() => asNonZeroFiniteNumber(-0)).toThrow(TypeError);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('rejects non-finite numbers', () => {
|
|
27
|
+
expect(() => asNonZeroFiniteNumber(Number.NaN)).toThrow(TypeError);
|
|
28
|
+
expect(() => asNonZeroFiniteNumber(Number.POSITIVE_INFINITY)).toThrow(
|
|
29
|
+
TypeError,
|
|
30
|
+
);
|
|
31
|
+
expect(() => asNonZeroFiniteNumber(Number.NEGATIVE_INFINITY)).toThrow(
|
|
32
|
+
TypeError,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('returns the same value for valid inputs', () => {
|
|
37
|
+
expect(asNonZeroFiniteNumber(5.5)).toBe(5.5);
|
|
38
|
+
expect(asNonZeroFiniteNumber(-10)).toBe(-10);
|
|
39
|
+
expect(asNonZeroFiniteNumber(1)).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test.each([
|
|
43
|
+
{ name: 'Number.NaN', value: Number.NaN },
|
|
44
|
+
{ name: 'Number.POSITIVE_INFINITY', value: Number.POSITIVE_INFINITY },
|
|
45
|
+
{ name: 'Number.NEGATIVE_INFINITY', value: Number.NEGATIVE_INFINITY },
|
|
46
|
+
{ name: '0', value: 0 },
|
|
47
|
+
] as const)(
|
|
48
|
+
`asNonZeroFiniteNumber($name) should throw a TypeError`,
|
|
49
|
+
({ value }) => {
|
|
50
|
+
expect(() => asNonZeroFiniteNumber(value)).toThrow(
|
|
51
|
+
new TypeError(`Expected a non-zero finite number, got: ${value}`),
|
|
52
|
+
);
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('isNonZeroFiniteNumber', () => {
|
|
58
|
+
test('correctly identifies non-zero finite numbers', () => {
|
|
59
|
+
expect(isNonZeroFiniteNumber(1)).toBe(true);
|
|
60
|
+
expect(isNonZeroFiniteNumber(-1)).toBe(true);
|
|
61
|
+
expect(isNonZeroFiniteNumber(3.14)).toBe(true);
|
|
62
|
+
expect(isNonZeroFiniteNumber(-2.5)).toBe(true);
|
|
63
|
+
expect(isNonZeroFiniteNumber(0.001)).toBe(true);
|
|
64
|
+
expect(isNonZeroFiniteNumber(-0.001)).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('correctly identifies zero', () => {
|
|
68
|
+
expect(isNonZeroFiniteNumber(0)).toBe(false);
|
|
69
|
+
expect(isNonZeroFiniteNumber(-0)).toBe(false);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('correctly identifies non-finite numbers', () => {
|
|
73
|
+
expect(isNonZeroFiniteNumber(Number.NaN)).toBe(false);
|
|
74
|
+
expect(isNonZeroFiniteNumber(Number.POSITIVE_INFINITY)).toBe(false);
|
|
75
|
+
expect(isNonZeroFiniteNumber(Number.NEGATIVE_INFINITY)).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('NonZeroFiniteNumber.is', () => {
|
|
80
|
+
test('same as isNonZeroFiniteNumber function', () => {
|
|
81
|
+
expect(NonZeroFiniteNumber.is(5)).toBe(isNonZeroFiniteNumber(5));
|
|
82
|
+
expect(NonZeroFiniteNumber.is(0)).toBe(isNonZeroFiniteNumber(0));
|
|
83
|
+
expect(NonZeroFiniteNumber.is(-1)).toBe(isNonZeroFiniteNumber(-1));
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('mathematical operations', () => {
|
|
88
|
+
const a = asNonZeroFiniteNumber(5.5);
|
|
89
|
+
const b = asNonZeroFiniteNumber(2.5);
|
|
90
|
+
const c = asNonZeroFiniteNumber(-3.5);
|
|
91
|
+
|
|
92
|
+
test('abs', () => {
|
|
93
|
+
expect(NonZeroFiniteNumber.abs(a)).toBe(5.5);
|
|
94
|
+
expect(NonZeroFiniteNumber.abs(c)).toBe(3.5);
|
|
95
|
+
expect(NonZeroFiniteNumber.abs(asNonZeroFiniteNumber(-1))).toBe(1);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('min and max', () => {
|
|
99
|
+
expect(NonZeroFiniteNumber.min(a, b)).toBe(2.5);
|
|
100
|
+
expect(NonZeroFiniteNumber.max(a, b)).toBe(5.5);
|
|
101
|
+
expect(NonZeroFiniteNumber.min(a, c)).toBe(-3.5);
|
|
102
|
+
expect(NonZeroFiniteNumber.max(a, c)).toBe(5.5);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('floor, ceil, round', () => {
|
|
106
|
+
expect(NonZeroFiniteNumber.floor(a)).toBe(5);
|
|
107
|
+
expect(NonZeroFiniteNumber.ceil(a)).toBe(6);
|
|
108
|
+
expect(NonZeroFiniteNumber.round(a)).toBe(6);
|
|
109
|
+
expect(NonZeroFiniteNumber.floor(c)).toBe(-4);
|
|
110
|
+
expect(NonZeroFiniteNumber.ceil(c)).toBe(-3);
|
|
111
|
+
expect(NonZeroFiniteNumber.round(c)).toBe(-3);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('add', () => {
|
|
115
|
+
expect(NonZeroFiniteNumber.add(a, b)).toBe(8);
|
|
116
|
+
expect(NonZeroFiniteNumber.add(a, c)).toBe(2);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('sub', () => {
|
|
120
|
+
expect(NonZeroFiniteNumber.sub(a, b)).toBe(3);
|
|
121
|
+
expect(NonZeroFiniteNumber.sub(a, c)).toBe(9);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('mul', () => {
|
|
125
|
+
expect(NonZeroFiniteNumber.mul(a, b)).toBe(13.75);
|
|
126
|
+
expect(NonZeroFiniteNumber.mul(a, c)).toBe(-19.25);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('div', () => {
|
|
130
|
+
expect(NonZeroFiniteNumber.div(a, b)).toBe(2.2);
|
|
131
|
+
expect(NonZeroFiniteNumber.div(a, asNonZeroFiniteNumber(2))).toBe(2.75);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('pow', () => {
|
|
135
|
+
expect(
|
|
136
|
+
NonZeroFiniteNumber.pow(
|
|
137
|
+
asNonZeroFiniteNumber(2),
|
|
138
|
+
asNonZeroFiniteNumber(3),
|
|
139
|
+
),
|
|
140
|
+
).toBe(8);
|
|
141
|
+
expect(
|
|
142
|
+
NonZeroFiniteNumber.pow(
|
|
143
|
+
asNonZeroFiniteNumber(3),
|
|
144
|
+
asNonZeroFiniteNumber(2),
|
|
145
|
+
),
|
|
146
|
+
).toBe(9);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('random', () => {
|
|
151
|
+
test('generates non-zero numbers within specified range (positive range)', () => {
|
|
152
|
+
const min = asNonZeroFiniteNumber(1.5);
|
|
153
|
+
const max = asNonZeroFiniteNumber(10.3);
|
|
154
|
+
|
|
155
|
+
for (let i = 0; i < 10; i++) {
|
|
156
|
+
const result = NonZeroFiniteNumber.random(min, max);
|
|
157
|
+
expect(result).toBeGreaterThanOrEqual(min);
|
|
158
|
+
expect(result).toBeLessThanOrEqual(max);
|
|
159
|
+
expect(NonZeroFiniteNumber.is(result)).toBe(true);
|
|
160
|
+
expect(result).not.toBe(0);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test('generates non-zero numbers within specified range (negative range)', () => {
|
|
165
|
+
const min = asNonZeroFiniteNumber(-10.3);
|
|
166
|
+
const max = asNonZeroFiniteNumber(-1.5);
|
|
167
|
+
|
|
168
|
+
for (let i = 0; i < 10; i++) {
|
|
169
|
+
const result = NonZeroFiniteNumber.random(min, max);
|
|
170
|
+
expect(result).toBeGreaterThanOrEqual(min);
|
|
171
|
+
expect(result).toBeLessThanOrEqual(max);
|
|
172
|
+
expect(NonZeroFiniteNumber.is(result)).toBe(true);
|
|
173
|
+
expect(result).not.toBe(0);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test('generates non-zero numbers within range that spans zero', () => {
|
|
178
|
+
const min = asNonZeroFiniteNumber(-5.5);
|
|
179
|
+
const max = asNonZeroFiniteNumber(5.5);
|
|
180
|
+
|
|
181
|
+
for (let i = 0; i < 10; i++) {
|
|
182
|
+
const result = NonZeroFiniteNumber.random(min, max);
|
|
183
|
+
expect(result).toBeGreaterThanOrEqual(min);
|
|
184
|
+
expect(result).toBeLessThanOrEqual(max);
|
|
185
|
+
expect(NonZeroFiniteNumber.is(result)).toBe(true);
|
|
186
|
+
expect(result).not.toBe(0);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('type assertions', () => {
|
|
192
|
+
test('type relationships', () => {
|
|
193
|
+
expectType<NonZeroFiniteNumber, number>('<=');
|
|
194
|
+
|
|
195
|
+
expectTypeOf(asNonZeroFiniteNumber(5.5)).toExtend<NonZeroFiniteNumber>();
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import { TsVerifiedInternals } from '../refined-number-utils.mjs';
|
|
3
|
+
|
|
4
|
+
type ElementType = NonZeroInt;
|
|
5
|
+
|
|
6
|
+
const typeNameInMessage = 'a non-zero integer';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
abs,
|
|
10
|
+
min: min_,
|
|
11
|
+
max: max_,
|
|
12
|
+
pow,
|
|
13
|
+
add,
|
|
14
|
+
sub,
|
|
15
|
+
mul,
|
|
16
|
+
div,
|
|
17
|
+
randomNonZero: random,
|
|
18
|
+
is,
|
|
19
|
+
castType,
|
|
20
|
+
} = TsVerifiedInternals.RefinedNumberUtils.operatorsForInteger<
|
|
21
|
+
ElementType,
|
|
22
|
+
undefined,
|
|
23
|
+
undefined
|
|
24
|
+
>({
|
|
25
|
+
integerOrSafeInteger: 'Integer',
|
|
26
|
+
nonZero: true,
|
|
27
|
+
MIN_VALUE: undefined,
|
|
28
|
+
MAX_VALUE: undefined,
|
|
29
|
+
typeNameInMessage,
|
|
30
|
+
} as const);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Checks if a number is a NonZeroInt.
|
|
34
|
+
* @param value The value to check.
|
|
35
|
+
* @returns `true` if the value is a NonZeroInt, `false` otherwise.
|
|
36
|
+
*/
|
|
37
|
+
export const isNonZeroInt = is;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Casts a number to a NonZeroInt type.
|
|
41
|
+
* @param value The value to cast.
|
|
42
|
+
* @returns The value as a NonZeroInt type.
|
|
43
|
+
* @throws {TypeError} If the value is not a non-zero integer.
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const x = asNonZeroInt(5); // NonZeroInt
|
|
47
|
+
* const y = asNonZeroInt(-3); // NonZeroInt
|
|
48
|
+
* // asNonZeroInt(0); // throws TypeError
|
|
49
|
+
* // asNonZeroInt(1.5); // throws TypeError
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export const asNonZeroInt = castType;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Namespace providing type-safe arithmetic operations for non-zero integers.
|
|
56
|
+
*
|
|
57
|
+
* All operations maintain the non-zero constraint, ensuring that results are always valid NonZeroInt values.
|
|
58
|
+
* Division operations return floor division results, and all arithmetic maintains integer precision.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const a = asNonZeroInt(10);
|
|
63
|
+
* const b = asNonZeroInt(-5);
|
|
64
|
+
*
|
|
65
|
+
* // Arithmetic operations
|
|
66
|
+
* const sum = NonZeroInt.add(a, b); // NonZeroInt (5)
|
|
67
|
+
* const diff = NonZeroInt.sub(a, b); // NonZeroInt (15)
|
|
68
|
+
* const product = NonZeroInt.mul(a, b); // NonZeroInt (-50)
|
|
69
|
+
* const quotient = NonZeroInt.div(a, b); // NonZeroInt (-2)
|
|
70
|
+
*
|
|
71
|
+
* // Utility operations
|
|
72
|
+
* const absolute = NonZeroInt.abs(b); // NonZeroInt (5)
|
|
73
|
+
* const power = NonZeroInt.pow(a, asNonZeroInt(2)); // NonZeroInt (100)
|
|
74
|
+
* const minimum = NonZeroInt.min(a, b); // NonZeroInt (-5)
|
|
75
|
+
* const maximum = NonZeroInt(a, b); // NonZeroInt (10)
|
|
76
|
+
*
|
|
77
|
+
* // Random generation
|
|
78
|
+
* const randomInt = NonZeroInt.random(); // NonZeroInt (random non-zero integer)
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export const NonZeroInt = {
|
|
82
|
+
/**
|
|
83
|
+
* Type guard to check if a value is a NonZeroInt.
|
|
84
|
+
* @param value The value to check.
|
|
85
|
+
* @returns `true` if the value is a non-zero integer, `false` otherwise.
|
|
86
|
+
*/
|
|
87
|
+
is,
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Returns the absolute value of a non-zero integer.
|
|
91
|
+
* @param a The non-zero integer.
|
|
92
|
+
* @returns The absolute value as a NonZeroInt.
|
|
93
|
+
*/
|
|
94
|
+
abs,
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Returns the smaller of two non-zero integers.
|
|
98
|
+
* @param a The first non-zero integer.
|
|
99
|
+
* @param b The second non-zero integer.
|
|
100
|
+
* @returns The minimum value as a NonZeroInt.
|
|
101
|
+
*/
|
|
102
|
+
min: min_,
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Returns the larger of two non-zero integers.
|
|
106
|
+
* @param a The first non-zero integer.
|
|
107
|
+
* @param b The second non-zero integer.
|
|
108
|
+
* @returns The maximum value as a NonZeroInt.
|
|
109
|
+
*/
|
|
110
|
+
max: max_,
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Generates a random non-zero integer.
|
|
114
|
+
* @returns A random NonZeroInt value.
|
|
115
|
+
*/
|
|
116
|
+
random,
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Raises a non-zero integer to the power of another non-zero integer.
|
|
120
|
+
* @param a The base non-zero integer.
|
|
121
|
+
* @param b The exponent non-zero integer.
|
|
122
|
+
* @returns `a ** b` as a NonZeroInt.
|
|
123
|
+
*/
|
|
124
|
+
pow,
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Adds two non-zero integers.
|
|
128
|
+
* @param a The first non-zero integer.
|
|
129
|
+
* @param b The second non-zero integer.
|
|
130
|
+
* @returns `a + b` as a NonZeroInt.
|
|
131
|
+
*/
|
|
132
|
+
add,
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Subtracts one non-zero integer from another.
|
|
136
|
+
* @param a The minuend non-zero integer.
|
|
137
|
+
* @param b The subtrahend non-zero integer.
|
|
138
|
+
* @returns `a - b` as a NonZeroInt.
|
|
139
|
+
*/
|
|
140
|
+
sub,
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Multiplies two non-zero integers.
|
|
144
|
+
* @param a The first non-zero integer.
|
|
145
|
+
* @param b The second non-zero integer.
|
|
146
|
+
* @returns `a * b` as a NonZeroInt.
|
|
147
|
+
*/
|
|
148
|
+
mul,
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Divides one non-zero integer by another using floor division.
|
|
152
|
+
* @param a The dividend non-zero integer.
|
|
153
|
+
* @param b The divisor non-zero integer.
|
|
154
|
+
* @returns `⌊a / b⌋` as a NonZeroInt.
|
|
155
|
+
*/
|
|
156
|
+
div,
|
|
157
|
+
} as const;
|
|
158
|
+
|
|
159
|
+
expectType<
|
|
160
|
+
keyof typeof NonZeroInt,
|
|
161
|
+
keyof TsVerifiedInternals.RefinedNumberUtils.NumberClass<ElementType, 'int'>
|
|
162
|
+
>('=');
|
|
163
|
+
|
|
164
|
+
expectType<
|
|
165
|
+
typeof NonZeroInt,
|
|
166
|
+
TsVerifiedInternals.RefinedNumberUtils.NumberClass<ElementType, 'int'>
|
|
167
|
+
>('<=');
|