Question

Check Whether a String Is Numeric in TypeScript

Question

How can I correctly check whether a string contains a numeric value in TypeScript?

Calling isNaN directly with a string causes a TypeScript error because its typed argument is a number:

isNaN("9BX46B6A");

Using parseFloat does not solve the validation problem because it accepts a valid numeric prefix. For example, parseFloat("9BX46B6A") returns 9, so this produces an incorrect result:

isNaN(parseFloat("9BX46B6A")); // false

How should this be implemented correctly, instead of comparing the parsed number's string length with the original input?

static isNaNModified = (inputStr: string) => {
  const numericRepr = parseFloat(inputStr);
  return isNaN(numericRepr) || numericRepr.toString().length !== inputStr.length;
};

Short Answer

You will learn why parseFloat() is not a strict string validator, how Number() and Number.isFinite() can validate numeric input, and when a regular expression is the better choice for decimal-only formats.

Concept

A numeric-string check has two separate jobs:

  1. Convert or inspect the whole input.
  2. Reject formats your application does not allow.

parseFloat() is designed for parsing text that starts with a number. It intentionally stops when it reaches an invalid character:

parseFloat("9BX46B6A"); // 9
parseFloat("12px");     // 12

That behavior is useful when reading values such as CSS-like text, but it is not appropriate when validating user input.

For general JavaScript numeric conversion, use Number() instead. It requires the entire non-whitespace string to be convertible:

Number("9BX46B6A"); // NaN
Number("12px");     // NaN
Number("12.5");     // 12.5

Then use Number.isFinite() to reject NaN, Infinity, and -Infinity:

function isNumericString(value: string): boolean {
  const trimmed = value.trim();
  return trimmed !== "" && Number.isFinite(Number(trimmed));
}

The empty-string check matters because Number("") and Number(" ") both return 0. Usually, an empty form field should not count as a number.

The word numeric can mean different things. Number() accepts JavaScript number formats such as "0xFF" (hexadecimal). If you only allow ordinary decimal input such as "12", "-3.5", or "1e4", validate the textual format with a regular expression instead.

Mental Model

Think of parseFloat() as a cashier who reads a price label only until it becomes confusing. Given "9BX46B6A", the cashier reads 9 and ignores the remaining letters.

Number() is like a strict scanner: it must understand the entire label or it rejects it.

A regular expression is like a custom admission rule at a door. You can say exactly which characters and layouts are allowed, such as optional + or -, digits, one decimal point, and an optional exponent.

Take Quiz

Syntax and Examples

For a general finite JavaScript number, trim whitespace, reject an empty value, convert with Number(), and test with Number.isFinite():

function isNumericString(value: string): boolean {
  const trimmed = value.trim();
  return trimmed !== "" && Number.isFinite(Number(trimmed));
}

console.log(isNumericString("42"));        // true
console.log(isNumericString(" -3.14 "));   // true
console.log(isNumericString("1e6"));       // true
console.log(isNumericString("9BX46B6A"));  // false
console.log(isNumericString("12px"));      // false
console.log(isNumericString(""));          // false
console.log(isNumericString("Infinity"));  // false

If your input must be a decimal number only, use a pattern. This version permits integers, decimals, signs, and scientific notation, but rejects hexadecimal values:

const decimalNumberPattern = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/;

function isDecimalString(value: string): boolean {
  return decimalNumberPattern.test(value.trim());
}

console.log(isDecimalString("42"));      // true
console.log(isDecimalString(".5"));      // true
console.log(isDecimalString("-1.25e3")); // true
console.log(isDecimalString("0xFF"));    // false
console.log(isDecimalString("12px"));    // false

Use the first function when your application accepts JavaScript-style numeric values. Use the second when the text format itself matters.

Step by Step Execution

Consider this function and input:

function isNumericString(value: string): boolean {
  const trimmed = value.trim();
  return trimmed !== "" && Number.isFinite(Number(trimmed));
}

const result = isNumericString(" 9BX46B6A ");

Step by step:

  1. value.trim() removes the surrounding spaces, producing "9BX46B6A".
  2. trimmed !== "" is true, so evaluation continues.
  3. Number("9BX46B6A") attempts to convert the whole string.
  4. The letters make the complete conversion invalid, so the result is NaN.
  5. Number.isFinite(NaN) is false.
  6. The function returns false.

Now try isNumericString(" 9 "):

  1. Trimming produces "9".
  2. The string is not empty.
  3. Number("9") returns 9.
  4. Number.isFinite(9) is true.
  5. The function returns true.

Real World Use Cases

Numeric-string validation is common when values arrive as text:

  • Form inputs: Validate quantities, prices, ages, and measurements before submitting a form.
  • Query parameters: Check a URL value such as ?page=3 before using it for pagination.
  • CSV imports: Reject rows where an amount contains accidental text like "19USD".
  • Configuration files: Validate environment variables such as PORT="3000".
  • API boundaries: Verify string fields from external systems before calculations or database writes.

Validation should happen before using the converted number:

const pageText = "3";

if (!isNumericString(pageText)) {
  throw new Error("page must be a finite number");
}

const page = Number(pageText);
Take Quiz

Real Codebase Usage

In production code, validation usually converts the value once and then uses the converted result. This avoids parsing the same text multiple times.

function parseFiniteNumber(value: string): number | undefined {
  const trimmed = value.trim();

  if (trimmed === "") {
    return undefined;
  }

  const numberValue = Number(trimmed);

  if (!Number.isFinite(numberValue)) {
    return undefined;
  }

  return numberValue;
}

const price = parseFiniteNumber("24.99");

if (price === undefined) {
  console.error("Enter a valid price.");
} else {
  console.log(price * 1.2);
}

This is a guard clause pattern: invalid values return early, leaving the successful path simple.

Projects also often add business rules after numeric validation:

function parsePositiveInteger(value: string): number | undefined {
  if (!/^\d+$/.test(value.trim())) {
    return undefined;
  }

  const result = Number(value.trim());
  return Number.isSafeInteger(result) && result > 0 ? result : undefined;
}

This is appropriate for values such as item counts, IDs, and page numbers, where decimals, signs, and scientific notation should be rejected.

Common Mistakes

Using parseFloat() as validation

// Broken for strict validation
const valid = !isNaN(parseFloat("12px")); // true

parseFloat() accepts a numeric prefix. Use Number() for whole-string conversion, or use a regular expression for a specific format.

Passing a string to global isNaN()

// TypeScript reports an error with standard typings
isNaN("42");

JavaScript may coerce values at runtime, but TypeScript correctly encourages you to be explicit. Convert first, or use Number.isFinite(Number(value)).

Forgetting empty strings

Number("");    // 0
Number("   "); // 0

Check value.trim() !== "" before conversion if blank input is invalid.

Comparing string lengths after parsing

// Fragile and incorrect for many valid representations
parseFloat("01").toString().length !== "01".length;

Different strings can represent the same number: "01", "1.0", "1e3", and " 1 ". Numeric conversion normalizes them, so length comparisons do not reliably validate input.

Accepting infinity accidentally

!Number.isNaN(Number("Infinity")); // true

If your application needs an ordinary finite number, use Number.isFinite() rather than only checking for NaN.

Using a loose equality check

// Avoid
if (value == "") {
  // Some non-string values can behave unexpectedly.
}

When working with strings, use value.trim() === "" and strict equality.

Comparisons

Tool or approachWhole string required?"12px"Empty stringBest use
parseFloat(value)NoParses as 12NaNReading a numeric prefix intentionally
Number(value)YesNaNConverts to 0Converting a complete JavaScript numeric value
Number.isNaN(value)Not a converterNot applicableNot applicableTesting whether an existing number is NaN
Number.isFinite(Number(value))Yesfalsetrue without an extra blank checkValidating finite numeric values
Regular expressionYou decideUsually falseUsually falseEnforcing an exact text format

isNaN() is the older global function. It coerces its argument at runtime, which can make its behavior surprising. Prefer Number.isNaN() when you already have a number, and Number.isFinite(Number(text)) when validating numeric text.

For integer-only fields, add Number.isInteger() or use an integer-specific regular expression:

const isIntegerString = (value: string) => /^[+-]?\d+$/.test(value.trim());
Take Quiz

Cheat Sheet

// General finite numeric string
function isNumericString(value: string): boolean {
  const trimmed = value.trim();
  return trimmed !== "" && Number.isFinite(Number(trimmed));
}
// Decimal notation only: 12, -3.5, .25, 1e6
const isDecimalString = (value: string): boolean =>
  /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/.test(value.trim());
// Positive whole-number text: 1, 25, 300
const isPositiveIntegerString = (value: string): boolean =>
  /^[1-9]\d*$/.test(value.trim());

Rules to remember:

  • Do not use parseFloat() for strict validation.
  • Reject blank input before calling Number().
  • Use Number.isFinite() to reject NaN and infinities.
  • Use a regular expression when permitted formatting matters.
  • Parse once and reuse the parsed number when possible.

FAQ

Why does parseFloat("9BX46B6A") return 9?

parseFloat() parses from the beginning of a string and stops at the first character that cannot be part of a floating-point number. It is not a full-string validator.

Why does TypeScript complain about isNaN("9")?

TypeScript's standard declaration expects a number for isNaN(). This helps prevent implicit conversion mistakes. Convert the string explicitly instead.

Is Number("12px") a number?

No. It returns NaN because Number() requires the entire trimmed string to be a valid numeric representation.

Does Number() accept spaces around a number?

Yes. Number(" 42 ") returns 42. Trim explicitly if you also need to reject whitespace-only input.

Does Number() accept hexadecimal values such as "0xFF"?

Yes, Number("0xFF") returns 255. Use a decimal regular expression if hexadecimal input should be rejected.

Should Infinity count as numeric?

It depends on the domain, but it is usually invalid for user-entered quantities, prices, and database values. Number.isFinite() rejects it.

How do I validate an integer instead of any number?

Use an integer regular expression such as /^[+-]?\d+$/, or convert using Number() and then check Number.isInteger(result).

Is a regex always necessary for numeric strings?

No. Number.isFinite(Number(value)) is enough when JavaScript's accepted number formats match your requirements. Use a regex only when you need a stricter textual format.

Take Quiz

Mini Project

Description

Build a small TypeScript utility that validates an order quantity entered as text. Order quantities must be positive whole numbers, so values such as "3" are valid while "3.5", "3items", and blank text are invalid.

Goal

Create a function that converts a valid quantity string to a number and returns undefined for invalid input.

Requirements

Validate the entire input rather than only a numeric prefix. Reject empty or whitespace-only input. Accept only positive whole numbers. Reject decimal values, signs, letters, and zero. Return the parsed number when the input is valid.

Take Quiz

Keep learning

Related questions

View more