How to write isNumber() in JavaScript?
Categories:
Mastering isNumber(): Robust Number Validation in JavaScript

Learn various techniques to reliably check if a variable is a number in JavaScript, covering primitive types, objects, and edge cases.
Determining if a given variable is a number in JavaScript might seem straightforward, but the language's flexible type system introduces several nuances. From primitive numbers to Number
objects, and special values like NaN
and Infinity
, a robust isNumber()
function needs to handle various scenarios. This article explores different approaches, their strengths, and their weaknesses, helping you write reliable number validation logic.
The Basic Approach: typeof
Operator
The typeof
operator is the most direct way to check the primitive type of a variable. When applied to a number, it returns the string 'number'
. This works well for literal numbers and variables holding numeric values.
function isNumberBasic(value) {
return typeof value === 'number';
}
console.log(isNumberBasic(123)); // true
console.log(isNumberBasic(3.14)); // true
console.log(isNumberBasic(-5)); // true
console.log(isNumberBasic('hello')); // false
console.log(isNumberBasic(true)); // false
console.log(isNumberBasic(null)); // false
console.log(isNumberBasic(undefined)); // false
Basic isNumber
check using typeof
.
typeof value === 'number'
is a good start, it has limitations. It returns true
for NaN
(Not-a-Number) and Infinity
, which might not always be desired in a strict number validation.Handling NaN
and Infinity
For a more robust isNumber()
function, you often need to exclude NaN
and Infinity
. JavaScript provides Number.isNaN()
and Number.isFinite()
for this purpose. Number.isNaN()
is preferred over the global isNaN()
because the global version attempts to coerce its argument to a number, leading to unexpected results (e.g., isNaN('hello')
is true
). Number.isFinite()
checks if a value is a finite number, excluding NaN
, Infinity
, and -Infinity
.
function isNumberRobust(value) {
return typeof value === 'number' && Number.isFinite(value);
}
console.log(isNumberRobust(123)); // true
console.log(isNumberRobust(3.14)); // true
console.log(isNumberRobust(-5)); // true
console.log(isNumberRobust(NaN)); // false
console.log(isNumberRobust(Infinity)); // false
console.log(isNumberRobust(-Infinity)); // false
console.log(isNumberRobust('123')); // false (still not a number primitive)
Robust isNumber
check excluding NaN
and Infinity
.
flowchart TD A[Start: Check value] --> B{Is typeof value === 'number'?} B -- No --> D[Result: false] B -- Yes --> C{Is Number.isFinite(value)?} C -- No --> D C -- Yes --> E[Result: true]
Decision flow for a robust isNumber
function.
Considering Number
Objects and Type Coercion
JavaScript also has a Number
object wrapper (new Number(123)
). While typeof new Number(123)
returns 'object'
, you might want to treat these as numbers. Additionally, sometimes you might want to check if a value can be coerced into a valid number (e.g., a string like '123'
).
function isNumberCoercible(value) {
if (typeof value === 'number' && Number.isFinite(value)) {
return true;
}
// Handle Number objects
if (value instanceof Number && Number.isFinite(value.valueOf())) {
return true;
}
// Attempt coercion for strings
if (typeof value === 'string' && value.trim() !== '') {
const coerced = Number(value);
return Number.isFinite(coerced);
}
return false;
}
console.log(isNumberCoercible(123)); // true
console.log(isNumberCoercible(new Number(456))); // true
console.log(isNumberCoercible('789')); // true
console.log(isNumberCoercible(' 10.5 ')); // true
console.log(isNumberCoercible('abc')); // false
console.log(isNumberCoercible(null)); // false
console.log(isNumberCoercible(true)); // false
console.log(isNumberCoercible('')); // false
An isNumber
function that handles Number
objects and coercible strings.
isNumberCoercible
approach can be very useful in these scenarios, but be mindful of the performance implications of coercion if called frequently.Summary of Approaches
Choosing the right isNumber()
implementation depends on your specific requirements. Here's a quick overview:

Comparison of different isNumber
implementations.
Basic (typeof
)
function isNumberBasic(value) {
return typeof value === 'number';
}
// Handles primitive numbers, but includes NaN and Infinity.
Robust (typeof
+ isFinite
)
function isNumberRobust(value) {
return typeof value === 'number' && Number.isFinite(value);
}
// Best for strict numeric validation, excludes NaN and Infinity.
Coercible (Advanced)
function isNumberCoercible(value) {
if (typeof value === 'number' && Number.isFinite(value)) return true;
if (value instanceof Number && Number.isFinite(value.valueOf())) return true;
if (typeof value === 'string' && value.trim() !== '') {
const coerced = Number(value);
return Number.isFinite(coerced);
}
return false;
}
// Useful for user input, handles Number objects and coercible strings.