Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Type Checks

Spread the love

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at how to do type checks properly in JavaScript so that we won’t run into data type errors when we’re running our apps.

typeof Operator

We can use the typeof operator to check for primitive data types and also some object types like functions.

These checks are needed so that we know that we’re working on the right type of data. For instance, we don’t want to use the + operator with strings when we actually want to add numbers together.

To use it, we add typeof before the value that we want to check. Possible values that are returned by the typeof operator are the following:

  • Undefined — "undefined"
  • Null — "object"
  • Boolean — "boolean"
  • Number — "number"
  • BigInt (new in ECMAScript 2020) — "bigint"
  • String — "string"
  • Symbol (new in ECMAScript 2015) — "symbol"
  • Function object (implements [[Call]] in ECMA-262 terms) — "function"
  • Any other object — "object"

These are all the possible type name strings that typeof can return. Most of these are primitive value types, except for 'object' and 'function' .

Note that typeof null returns 'object' . This is a bug, but since it breaks too much existing code for this to be corrected, it’s kept the way it is.

For instance, we can do the following checks with the typeof operator:

typeof 3 === 'number';
typeof 3.1 === 'number';
typeof(40) === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number';

The code above all return true. As we can see from the code above, numbers, Infinity and NaN all return the type 'number' when we use them with the typeof as operands.

An example for a BigInt check is the following:

typeof 41n === 'bigint';

BigInts have an n after the numeric literal to distinguish them from normal numbers. Also, they can only be integers and can only operate on other BigInts in most cases.

To check for strings we can write something like the following:

typeof '' === 'string';
typeof 'bla' === 'string';
typeof `template` === 'string';

This works for both normal and template strings.

To check for booleans, we can write:

typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(0) === 'boolean';
typeof !!(1) === 'boolean';

Boolean() and !! do the same thing. They both convert the argument or operand to a boolean. The expressions above all return true .

To check for symbols, we can write:

typeof Symbol() === 'symbol'
typeof Symbol('foo') === 'symbol'
typeof Symbol.iterator === 'symbol'

The expressions above all return true .

And to check for functions, we can write:

typeof () => {} === 'function';
typeof class C {} === 'function';
typeof Math.sin === 'function';

Note that since classes are just syntactic sugar for constructor functions in JavaScript, classes when used with typeof returns 'function' . The expressions above all return true .

To check if something is an object, we can write something like:

typeof {a: 1} === 'object';
typeof [1, 2, 3] === 'object';
typeof new Date() === 'object';

The expressions above all return true .

We should use wrapper objects for primitive values, so the following are useless and confusing:

typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';

All 3 expressions are true because they all have types 'object' . This isn’t a problem with object literals since they return the types we expect.

However, these don’t and they don’t do anything better than the literals, so we should avoid using constructors for defining primitive values.

The typeof operator doesn’t work with undeclared variables since ES2015.

For instance, if foo isn’t declared, then in ES2015 or later, then typeof foo will throw an error in our code.

Whereas before ES2015, typeof foo returns undefined if the variable is undeclared.

With block-scoped variables or constants, we can only do operations on them when the variable is declared. For instance, the following:

typeof foo === 'undefined';
let foo;

will give us a ReferenceError.

Therefore, we should be careful when using the typeof operator so we don’t cause more crashes during our checks.

Conclusion

The typeof operator lets us type checks mainly on primitive values. However, we can also use it to check if a function or class is a function.

Other kinds of objects will return 'object' with the typeof operator so it isn’t that useful.

Leave a Reply

Your email address will not be published.

If you like the content of this blog, subscribe to my email list to get exclusive articles not available to anyone else.