Published on 01/08/2021 by

programming

javascript

JavaScript (JS) isn't exactly

for being robust or terse - it's quite the opposite, it stands behind the notion of "I'll take whatever you throw at me". JS is a , developers won't have to explicitly define the type of data they're using. This can make things a lot simpler, but also a lot more complicated at the same time as we don't know what the data we are receiving will be or what we'll be able to do with it.Let's take a simple `addNumbers`

function:

1function addNumbers(first, second) {2 return first + second;3}

1addNumbers(1, 2); // logs 32typeof addNumbers(1, 2); // logs "number"

Great! We can feed two arguments in as numbers and get the sum as a number for the result. That means we can do number specific operations like `.toFixed`

. But if we pass in a string as the first argument...

1addNumbers("1", 2); // logs "12"2typeof addNumbers("1", 2); // logs "string"

Now our add function, intended for adding *numbers* is returning text! Even worse, if we were expecting a number to be returned and we tried using a number-specific method like `.toFixed`

, our app would throw an error:

`addNumbers(...).toFixed is not a function`

The situation above is unlikely to happen but not impossible (developer mistake). What *is* more likely is your app accepting user input, and we need to add validation in our `addNumbers`

function so that our app isn't just trying to add *any* two things together. But how can we transform the two arguments in `addNumbers`

into numbers and then confirm they are valid?

`parseInt`

`parseInt`

(also available under `Number.parseInt`

with same functionality) accepts two parameters, the first being the value to attempt to coerce into a number and the second is the radix or base.

1parseInt("100", 10); // 100

It's good to explicitly set the radix as `10`

(since we count in base 10) as if the input string begins with "0x", this represents an octal and the default radix will change to 16 (hexadecimal), producing different results.

An oddity to note with `parseInt`

is that it will parse the string character by character until it finds an invalid character for the specified radix. To show this better, see below how the same input can result in two different outputs:

1parseInt("0xf", 10); // 0, stops when reaching "x"2parseInt("99blake", 10); // 99, stops when reaching "b"3parseInt("0xf", 16); // 15, 0xf is 15 in hexadecimal (base 16)

`isNaN()`

`isNaN`

is a function available in the global scope and it allows us to know if a given input is "not a number" (NaN). We can inverse this to check if an input *is* a number.

1!isNaN(1); // === true, 1 is a number!

Great, we should expect to see that entering a string would return `false`

because a string is *obviously* not a number.

1!isNaN(""); // === true, what??

This function only validates that the value, when coerced to a number using the `Number`

constructor does not strictly equal itself. A quick reminder on a weird quirk: `NaN`

is the only value in JS that does not strictly equal itself:

1NaN === NaN; // false

Internally, `isNaN`

works similarly to this pseudocode:

1function parseInt(value) {2 const n = Number(value);3 return n !== n;4}

So when we convert an empty string to a number using the `Number`

constructor, what do we get?

1Number(""); // 020 === 0; // true3// therefore..4isNaN(""); // false

If you actually only want to test that a value is/isn't strictly `NaN`

, prefer `Number.isNaN()`

instead, which is more robust and also ensures that the type of the value is `number`

using `typeof`

`typeof x === "number"`

The `typeof`

operator returns the type of the data after it as a string:

1let a = 1;2typeof a; // "number"

This is more accurate than `isNaN`

as it will not accept strings since `typeof (any string)`

evaluates to `"string"`

`Number.isFinite`

and `Number.isInteger`

`Number.isFinite`

only returns true if the value given is of type "number" and the value is within positive infinity and negative infinity (basically any valid number).

If you want to ensure that your data is strictly an integer (not a floating point number like `2.31412`

), prefer `Number.isInteger`

instead which will return `false`

when provided with a floating point number that cannot be represented as an integer. Note that floating point numbers that are large enough will be rounded and then can be represented as an integer, thus passing the check:

1Number.isInteger(5.0); // true2Number.isInteger(5.000000000000001); // false3Number.isInteger(5.0000000000000001); // true

1function addNumbers(first, second) {2 // parseFloat allows us to convert a string into3 // a number with floating point precision4 first = parseFloat(first);5 second = parseFloat(second);6 // are the arguments valid numbers after being converted from a string?7 if (!Number.isFinite(first))8 throw new Error("first argument must be an integer");9 if (!Number.isFinite(second))10 throw new Error("second argument must be an integer");11 return first + second;12}

1addNumbers("1", 2); // 3! yay2// also works with other wonky combinations3addNumbers("1", "1"); // 24addNumbers("1", "1"); // 25addNumbers(1, "1"); // 26// errors when passing an invalid number7addNumbers("blablah blah", 2);8addNumbers("-", 2); // Error: first argument must be an integer9addNumbers(1); // Error: second argument must be an integer

Subscribe to the **Nevuletter** so you never miss new posts.

## Comments

## • 0

You need to be signed in to comment