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