isNumber
Determines whether a value is a number type with enhanced type safety. Provides reliable number type detection using native typeof check, identifying all number values including integers, floats, special numeric values (NaN, Infinity), and both positive and negative numbers.
Signature
const isNumber: (value?: unknown) => value is number
Parameters
| Name | Type | Description |
|---|---|---|
value | - | Value to test for number type |
Returns
Type-safe boolean indicating whether the value is a number
Examples
Basic number detection
import { isNumber } from '@winglet/common-utils';
// True cases - number type
console.log(isNumber(42)); // true
console.log(isNumber(-17)); // true
console.log(isNumber(3.14)); // true
console.log(isNumber(0)); // true
console.log(isNumber(-0)); // true
console.log(isNumber(Infinity)); // true
console.log(isNumber(-Infinity)); // true
console.log(isNumber(NaN)); // true (NaN is of type number)
console.log(isNumber(Number.MAX_VALUE)); // true
console.log(isNumber(Number.MIN_VALUE)); // true
console.log(isNumber(1e-10)); // true (scientific notation)
console.log(isNumber(0x10)); // true (hexadecimal)
console.log(isNumber(0b101)); // true (binary)
console.log(isNumber(0o77)); // true (octal)
// False cases - not number type
console.log(isNumber('42')); // false (string)
console.log(isNumber('3.14')); // false (string)
console.log(isNumber(true)); // false (boolean)
console.log(isNumber(null)); // false
console.log(isNumber(undefined)); // false
console.log(isNumber({})); // false (object)
console.log(isNumber([])); // false (array)
console.log(isNumber(BigInt(42))); // false (bigint, not number)
Form validation with number checking
interface FormData {
age: unknown;
price: unknown;
quantity: unknown;
}
function validateNumericFields(formData: FormData) {
const errors: string[] = [];
if (!isNumber(formData.age)) {
errors.push('Age must be a number');
} else if (isNaN(formData.age) || formData.age < 0 || formData.age > 150) {
errors.push('Age must be a valid number between 0 and 150');
}
if (!isNumber(formData.price)) {
errors.push('Price must be a number');
} else if (isNaN(formData.price) || formData.price < 0) {
errors.push('Price must be a valid positive number');
}
if (!isNumber(formData.quantity)) {
errors.push('Quantity must be a number');
} else if (!Number.isInteger(formData.quantity) || formData.quantity < 1) {
errors.push('Quantity must be a positive integer');
}
return errors;
}
Mathematical operations with type safety
function safeMath(a: unknown, b: unknown, operation: '+' | '-' | '*' | '/') {
if (!isNumber(a) || !isNumber(b)) {
throw new Error('Both operands must be numbers');
}
if (isNaN(a) || isNaN(b)) {
throw new Error('Cannot perform math with NaN values');
}
if (!isFinite(a) || !isFinite(b)) {
throw new Error('Cannot perform math with infinite values');
}
// TypeScript knows a and b are numbers
switch (operation) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/':
if (b === 0) throw new Error('Division by zero');
return a / b;
}
}
// Usage
console.log(safeMath(10, 5, '+')); // 15
console.log(safeMath(10, 2, '/')); // 5
// safeMath('10', 5, '+') // throws Error: Both operands must be numbers
API response validation
interface ApiResponse {
total: unknown;
count: unknown;
average: unknown;
}
function validateApiResponse(response: ApiResponse) {
const errors: string[] = [];
if (!isNumber(response.total)) {
errors.push('Total must be a number');
} else if (response.total < 0) {
errors.push('Total cannot be negative');
}
if (!isNumber(response.count)) {
errors.push('Count must be a number');
} else if (!Number.isInteger(response.count) || response.count < 0) {
errors.push('Count must be a non-negative integer');
}
if (!isNumber(response.average)) {
errors.push('Average must be a number');
} else if (isNaN(response.average)) {
errors.push('Average cannot be NaN');
}
if (errors.length > 0) {
throw new Error(`API validation failed: ${errors.join(', ')}`);
}
return response as { total: number; count: number; average: number };
}
Array processing with number filtering
function processNumericArray(data: unknown[]): {
numbers: number[];
validNumbers: number[];
sum: number;
average: number;
} {
const numbers = data.filter(isNumber);
const validNumbers = numbers.filter(n => !isNaN(n) && isFinite(n));
const sum = validNumbers.reduce((acc, n) => acc + n, 0);
const average = validNumbers.length > 0 ? sum / validNumbers.length : 0;
return {
numbers,
validNumbers,
sum,
average
};
}
// Usage
const mixed = [1, '2', 3.14, 'hello', NaN, Infinity, null, 42, true];
const result = processNumericArray(mixed);
console.log(result);
// {
// numbers: [1, 3.14, NaN, Infinity, 42],
// validNumbers: [1, 3.14, 42],
// sum: 46.14,
// average: 15.38
// }
Configuration validation
interface ServerConfig {
port?: unknown;
timeout?: unknown;
maxConnections?: unknown;
retryDelay?: unknown;
}
function validateServerConfig(config: ServerConfig) {
const validated = {
port: 3000,
timeout: 30000,
maxConnections: 100,
retryDelay: 1000
};
if (config.port !== undefined) {
if (!isNumber(config.port)) {
throw new Error('Port must be a number');
}
if (!Number.isInteger(config.port) || config.port < 1 || config.port > 65535) {
throw new Error('Port must be an integer between 1 and 65535');
}
validated.port = config.port;
}
if (config.timeout !== undefined) {
if (!isNumber(config.timeout)) {
throw new Error('Timeout must be a number');
}
if (config.timeout <= 0) {
throw new Error('Timeout must be positive');
}
validated.timeout = config.timeout;
}
return validated;
}
Statistical calculations
function calculateStatistics(values: unknown[]) {
const numbers = values.filter(isNumber).filter(n => !isNaN(n) && isFinite(n));
if (numbers.length === 0) {
return { error: 'No valid numbers provided' };
}
const sum = numbers.reduce((acc, n) => acc + n, 0);
const mean = sum / numbers.length;
const variance = numbers.reduce((acc, n) => acc + (n - mean) ** 2, 0) / numbers.length;
const stdDev = Math.sqrt(variance);
const sorted = [...numbers].sort((a, b) => a - b);
const median = sorted.length % 2 === 0
? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2
: sorted[Math.floor(sorted.length / 2)];
return {
count: numbers.length,
sum,
mean,
median,
variance,
standardDeviation: stdDev,
min: Math.min(...numbers),
max: Math.max(...numbers)
};
}
Playground
import { isNumber } from '@winglet/common-utils'; // True cases - number type console.log(isNumber(42)); // true console.log(isNumber(-17)); // true console.log(isNumber(3.14)); // true console.log(isNumber(0)); // true console.log(isNumber(-0)); // true console.log(isNumber(Infinity)); // true console.log(isNumber(-Infinity)); // true console.log(isNumber(NaN)); // true (NaN is of type number) console.log(isNumber(Number.MAX_VALUE)); // true console.log(isNumber(Number.MIN_VALUE)); // true console.log(isNumber(1e-10)); // true (scientific notation) console.log(isNumber(0x10)); // true (hexadecimal) console.log(isNumber(0b101)); // true (binary) console.log(isNumber(0o77)); // true (octal) // False cases - not number type console.log(isNumber('42')); // false (string) console.log(isNumber('3.14')); // false (string) console.log(isNumber(true)); // false (boolean) console.log(isNumber(null)); // false console.log(isNumber(undefined)); // false console.log(isNumber({})); // false (object) console.log(isNumber([])); // false (array) console.log(isNumber(BigInt(42))); // false (bigint, not number)
Notes
Important Note about NaN:
NaNis of typenumberin JavaScript, soisNumber(NaN)returnstrue- Use
isNaN()orNumber.isNaN()to check for NaN values specifically - Use
isFinite()to exclude both NaN and Infinity values
Special Number Values:
Infinityand-Infinityare valid numbersNaNis a valid number type (though not a valid numeric value)-0is treated as a number (and equals0)
Use Cases:
- Form field validation
- API parameter validation
- Mathematical operation guards
- Array filtering and processing
- Configuration validation
- Statistical calculations
Performance: Direct typeof check provides optimal performance.
Related Functions:
- Use
isInteger()for integer-specific checking - Use
isNaN()orNumber.isNaN()for NaN detection - Use
isFinite()to exclude NaN and Infinity - Use
Number.isSafeInteger()for safe integer range checking