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.