Skip to main content

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​

NameTypeDescription
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:

  • NaN is of type number in JavaScript, so isNumber(NaN) returns true
  • Use isNaN() or Number.isNaN() to check for NaN values specifically
  • Use isFinite() to exclude both NaN and Infinity values

Special Number Values:

  • Infinity and -Infinity are valid numbers
  • NaN is a valid number type (though not a valid numeric value)
  • -0 is treated as a number (and equals 0)

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() or Number.isNaN() for NaN detection
  • Use isFinite() to exclude NaN and Infinity
  • Use Number.isSafeInteger() for safe integer range checking