JavaScript is a dynamically typed language, which means the types of variables can change at runtime. Many interview questions involve recursively traversing values that contain different value types, and each type may require different handling (e.g. different code is needed to iterate over an array vs. an object). Understanding JavaScript types is crucial to solving questions like Deep Clone and Deep Equal.
Implement the following utility functions to determine the types of primitive values.
isBoolean(value): Return true if value is a boolean, false otherwise.isNumber(value): Return true if value is a number, false otherwise. Note that NaN is considered a number.isNull(value): Return true if value is null, false otherwise.isString(value): Return true if value is a string, false otherwise.isSymbol(value): Return true if value is a symbol primitive, false otherwise.isUndefined(value): Return true if value is undefined, false otherwise.The code here is short, but the interview skill is choosing the exact runtime check for each type instead of relying on coercion, truthiness, or overly broad checks.
Ask the narrow runtime question for each helper: "Is this value exactly this primitive type?" Most helpers are one-line predicates, but the details matter because JavaScript has a few special cases.
Each helper accepts one primitive category and rejects lookalikes. None of these checks should coerce the value, allocate wrapper objects, or call methods on the input.
Derive each predicate by first choosing the JavaScript operation that answers the exact question:
typeof when the runtime type string is unique for the primitive.null or undefined.These helpers fall into three buckets:
typeof works well for primitive categories like strings, numbers, and symbols.null and undefined need exact equality checks because typeof null is 'object' and null == undefined is true.value === true || value === false, which excludes truthy and falsy non-booleans.typeof NaN; // 'number'typeof null; // 'object'null == undefined; // true
isNumber(), isString(), and isSymbol() can use typeof directly. This also means NaN correctly counts as a number, as required by the prompt.
isNull() and isUndefined() use strict equality so the two values do not collapse into each other. value === null only accepts null, and value === undefined only accepts undefined.
isBoolean() checks for the two boolean primitive values explicitly. This avoids accidentally accepting truthy values like 1 or 'true', and avoids rejecting false just because it is falsy.
| Helper | Accepted primitive values | Main trap |
|---|---|---|
isBoolean | true, false | truthiness is not type checking |
isNumber | all numbers, including NaN | finiteness checks are too narrow |
isNull | only null | typeof null is 'object' |
isString | string primitives | boxed strings are objects |
isSymbol | symbol primitives | symbols are not strings |
isUndefined | only undefined | loose equality collapses null and undefined |
/*** @param {unknown} value* @returns {boolean}*/export function isBoolean(value) {return value === true || value === false;}/*** @param {unknown} value* @returns {boolean}*/export function isNumber(value) {return typeof value === 'number';}/*** @param {unknown} value* @returns {boolean}*/export function isNull(value) {return value === null;}/*** @param {unknown} value* @returns {boolean}*/export function isString(value) {return typeof value === 'string';}/*** @param {unknown} value* @returns {boolean}*/export function isSymbol(value) {return typeof value === 'symbol';}/*** @param {unknown} value* @returns {boolean}*/export function isUndefined(value) {return value === undefined;}
Using truthiness for booleans: Boolean(value) and !!value answer whether a value is truthy, not whether it is a boolean. They would treat 1, 'hello', and many objects as true, while isBoolean() should only return true for true and false.
Using loose equality for nullish values: value == null matches both null and undefined. That is useful in some application code, but not here because isNull() and isUndefined() must distinguish the two values.
Filtering out NaN: NaN is still a number according to typeof, and the question explicitly says it should return true from isNumber(). Do not use Number.isFinite() or similar checks that exclude NaN.
new String('hello') or new Boolean(false) have type 'object' and are not accepted by the corresponding primitive checks.isNumber() accepts every value whose runtime type is 'number', including NaN, Infinity, and -Infinity.typeof 1n is 'bigint', so isNumber(1n) would return false.console.log() statements will appear here.