0
# Numbers and Math
1
2
Specialized number validation including integers, safe integers, positive/negative numbers, even/odd checks, range validation, and mathematical properties.
3
4
## Capabilities
5
6
### Integer Type Checking
7
8
Check if a value is an integer or safe integer.
9
10
```typescript { .api }
11
/**
12
* Check if value is an integer
13
* @param value - Value to check
14
* @returns True if value is integer
15
*/
16
function isInteger(value: unknown): value is number;
17
18
/**
19
* Check if value is a safe integer (within safe integer range)
20
* @param value - Value to check
21
* @returns True if value is safe integer
22
*/
23
function isSafeInteger(value: unknown): value is number;
24
```
25
26
**Usage Examples:**
27
28
```typescript
29
import is from '@sindresorhus/is';
30
31
is.integer(42); // => true
32
is.integer(3.14); // => false
33
is.integer(Number.MAX_VALUE); // => false (too large to be precise)
34
35
is.safeInteger(42); // => true
36
is.safeInteger(Number.MAX_SAFE_INTEGER); // => true
37
is.safeInteger(Number.MAX_SAFE_INTEGER + 1); // => false
38
is.safeInteger(3.14); // => false
39
40
// Type guard usage
41
function processArrayIndex(index: unknown) {
42
if (is.safeInteger(index) && index >= 0) {
43
// index is now typed as number and guaranteed to be safe
44
return `Item at index ${index}`;
45
}
46
throw new Error('Invalid array index');
47
}
48
```
49
50
### Sign-based Number Checking
51
52
Check if numbers are positive or negative.
53
54
```typescript { .api }
55
/**
56
* Check if value is a positive number
57
* @param value - Value to check
58
* @returns True if value is positive number
59
*/
60
function isPositiveNumber(value: unknown): value is number;
61
62
/**
63
* Check if value is a negative number
64
* @param value - Value to check
65
* @returns True if value is negative number
66
*/
67
function isNegativeNumber(value: unknown): value is number;
68
```
69
70
**Usage Examples:**
71
72
```typescript
73
import is from '@sindresorhus/is';
74
75
is.positiveNumber(42); // => true
76
is.positiveNumber(0); // => false
77
is.positiveNumber(-5); // => false
78
is.positiveNumber('42'); // => false
79
80
is.negativeNumber(-42); // => true
81
is.negativeNumber(0); // => false
82
is.negativeNumber(5); // => false
83
84
// Type guard usage
85
function calculateDiscount(amount: unknown, discount: unknown) {
86
if (is.positiveNumber(amount) && is.positiveNumber(discount)) {
87
// Both are now typed as positive numbers
88
return amount - (amount * discount / 100);
89
}
90
throw new Error('Amount and discount must be positive numbers');
91
}
92
```
93
94
### Even and Odd Integer Checking
95
96
Check if integers are even or odd.
97
98
```typescript { .api }
99
/**
100
* Check if value is an even integer
101
* @param value - Value to check
102
* @returns True if value is even integer
103
*/
104
function isEvenInteger(value: unknown): value is number;
105
106
/**
107
* Check if value is an odd integer
108
* @param value - Value to check
109
* @returns True if value is odd integer
110
*/
111
function isOddInteger(value: unknown): value is number;
112
```
113
114
**Usage Examples:**
115
116
```typescript
117
import is from '@sindresorhus/is';
118
119
is.evenInteger(2); // => true
120
is.evenInteger(3); // => false
121
is.evenInteger(0); // => true
122
is.evenInteger(2.5); // => false
123
124
is.oddInteger(3); // => true
125
is.oddInteger(2); // => false
126
is.oddInteger(1.5); // => false
127
128
// Type guard usage
129
function processNumbers(numbers: unknown[]) {
130
const evens = numbers.filter(is.evenInteger);
131
const odds = numbers.filter(is.oddInteger);
132
133
console.log('Even numbers:', evens);
134
console.log('Odd numbers:', odds);
135
}
136
```
137
138
### Infinity Checking
139
140
Check if a value is positive or negative infinity.
141
142
```typescript { .api }
143
/**
144
* Check if value is Infinity or -Infinity
145
* @param value - Value to check
146
* @returns True if value is infinite
147
*/
148
function isInfinite(value: unknown): value is number;
149
```
150
151
**Usage Examples:**
152
153
```typescript
154
import is from '@sindresorhus/is';
155
156
is.infinite(Infinity); // => true
157
is.infinite(-Infinity); // => true
158
is.infinite(Number.POSITIVE_INFINITY); // => true
159
is.infinite(Number.NEGATIVE_INFINITY); // => true
160
is.infinite(42); // => false
161
is.infinite(NaN); // => false
162
163
// Type guard usage
164
function safeDivision(a: number, b: number) {
165
const result = a / b;
166
if (is.infinite(result)) {
167
throw new Error('Division resulted in infinity');
168
}
169
return result;
170
}
171
```
172
173
### Range Validation
174
175
Check if a number is within a specified range.
176
177
```typescript { .api }
178
/**
179
* Check if number is within specified range
180
* @param value - Number to check
181
* @param range - Range as single number (0 to range) or [min, max] tuple
182
* @returns True if value is in range
183
*/
184
function isInRange(value: number, range: number | [number, number]): value is number;
185
```
186
187
**Usage Examples:**
188
189
```typescript
190
import is from '@sindresorhus/is';
191
192
// Single number range (0 to range)
193
is.inRange(5, 10); // => true (0 <= 5 <= 10)
194
is.inRange(-2, 10); // => false (negative values not allowed)
195
is.inRange(15, 10); // => false (above range)
196
197
// Array range [min, max]
198
is.inRange(5, [0, 10]); // => true
199
is.inRange(5, [10, 20]); // => false
200
is.inRange(15, [10, 20]); // => true
201
202
// Range order doesn't matter
203
is.inRange(5, [10, 0]); // => true (same as [0, 10])
204
205
// Type guard usage (value is already number)
206
function processScore(score: number) {
207
if (is.inRange(score, [0, 100])) {
208
// score is guaranteed to be 0-100
209
const grade = score >= 90 ? 'A' : score >= 80 ? 'B' : 'C';
210
return grade;
211
}
212
throw new Error('Score must be between 0 and 100');
213
}
214
215
// Validation with unknown input
216
function validateAge(age: unknown) {
217
if (is.number(age) && is.inRange(age, [0, 120])) {
218
return age; // Valid age
219
}
220
throw new Error('Age must be a number between 0 and 120');
221
}
222
```
223
224
### Numeric String Validation
225
226
Check if a string represents a valid number.
227
228
```typescript { .api }
229
/**
230
* Check if string represents a valid number
231
* @param value - Value to check
232
* @returns True if value is numeric string
233
*/
234
function isNumericString(value: unknown): value is `${number}`;
235
```
236
237
**Usage Examples:**
238
239
```typescript
240
import is from '@sindresorhus/is';
241
242
is.numericString('42'); // => true
243
is.numericString('3.14'); // => true
244
is.numericString('-123'); // => true
245
is.numericString('1e10'); // => true
246
is.numericString('Infinity'); // => true
247
is.numericString('-Infinity'); // => true
248
249
is.numericString('NaN'); // => false
250
is.numericString('42px'); // => false
251
is.numericString(''); // => false
252
is.numericString(' '); // => false
253
is.numericString('hello'); // => false
254
255
// Type guard usage
256
function parseNumber(input: unknown) {
257
if (is.numericString(input)) {
258
// input is now typed as `${number}`
259
const num = Number(input);
260
return num;
261
}
262
throw new Error('Input is not a numeric string');
263
}
264
265
// Form validation
266
function validateFormInput(input: unknown) {
267
if (is.string(input) && is.numericString(input)) {
268
return Number(input);
269
}
270
return null;
271
}
272
```
273
274
## Usage Patterns
275
276
### Number Validation Chain
277
278
```typescript
279
import is from '@sindresorhus/is';
280
281
function validatePositiveInteger(value: unknown): number {
282
if (!is.number(value)) {
283
throw new Error('Value must be a number');
284
}
285
286
if (!is.integer(value)) {
287
throw new Error('Value must be an integer');
288
}
289
290
if (!is.positiveNumber(value)) {
291
throw new Error('Value must be positive');
292
}
293
294
return value;
295
}
296
297
// Usage
298
try {
299
const count = validatePositiveInteger(42); // OK
300
const invalid = validatePositiveInteger(-5); // throws
301
} catch (error) {
302
console.error(error.message);
303
}
304
```
305
306
### Mathematical Operations
307
308
```typescript
309
import is from '@sindresorhus/is';
310
311
function factorial(n: unknown): number {
312
if (!is.number(n) || !is.integer(n) || !is.positiveNumber(n)) {
313
throw new Error('Factorial requires a positive integer');
314
}
315
316
if (n === 0) return 1;
317
return n * factorial(n - 1);
318
}
319
320
function gcd(a: unknown, b: unknown): number {
321
if (!is.integer(a) || !is.integer(b)) {
322
throw new Error('GCD requires integers');
323
}
324
325
const absA = Math.abs(a as number);
326
const absB = Math.abs(b as number);
327
328
return absB === 0 ? absA : gcd(absB, absA % absB);
329
}
330
```
331
332
### Range-based Processing
333
334
```typescript
335
import is from '@sindresorhus/is';
336
337
function categorizeNumbers(numbers: unknown[]): {
338
positive: number[];
339
negative: number[];
340
zero: number[];
341
invalid: unknown[];
342
} {
343
const result = {
344
positive: [] as number[],
345
negative: [] as number[],
346
zero: [] as number[],
347
invalid: [] as unknown[]
348
};
349
350
for (const num of numbers) {
351
if (!is.number(num)) {
352
result.invalid.push(num);
353
} else if (is.positiveNumber(num)) {
354
result.positive.push(num);
355
} else if (is.negativeNumber(num)) {
356
result.negative.push(num);
357
} else {
358
result.zero.push(num); // Must be 0
359
}
360
}
361
362
return result;
363
}
364
```
365
366
### Safe Math Operations
367
368
```typescript
369
import is from '@sindresorhus/is';
370
371
function safeMath(a: unknown, b: unknown, operation: string): number {
372
if (!is.number(a) || !is.number(b)) {
373
throw new Error('Both operands must be numbers');
374
}
375
376
if (!is.safeInteger(a) || !is.safeInteger(b)) {
377
throw new Error('Operands must be safe integers');
378
}
379
380
let result: number;
381
switch (operation) {
382
case '+':
383
result = a + b;
384
break;
385
case '*':
386
result = a * b;
387
break;
388
default:
389
throw new Error('Unsupported operation');
390
}
391
392
if (!is.safeInteger(result)) {
393
throw new Error('Result exceeds safe integer range');
394
}
395
396
return result;
397
}
398
```
399
400
## Notes
401
402
- `isInteger()` uses `Number.isInteger()` internally
403
- `isSafeInteger()` checks if number is within `Number.MAX_SAFE_INTEGER` range
404
- Even/odd checking only works with integers; non-integers return `false`
405
- `isInRange()` accepts the number to check as first parameter (must already be a number)
406
- Range validation with single number creates range from 0 to that number
407
- Range validation with array accepts [min, max] in any order
408
- Numeric string validation excludes `'NaN'` but includes `'Infinity'` and `'-Infinity'`
409
- All number checks work with TypeScript type guards for compile-time type narrowing