JavaScript · Beginner

JavaScript Data Types: Primitives, Objects and typeof

9 min readUpdated September 24, 2026Every example verified

In short: JavaScript has seven primitive types: string, number, bigint, boolean, undefined, null and symbol. Everything else, including arrays and functions, is an object. Variables have no fixed type; the value does. The typeof operator reports a value's type as a string, with one historical quirk: typeof null is 'object'.

Values have types, variables do not

JavaScript is dynamically typed: a variable can hold a number now and a string later, and nothing is declared in advance. What has a type is the value itself, and the engine decides at run time what an operation means by looking at the types involved. That is why "5" + 1 is the string "51" while "5" * 1 is the number 5. Understanding the types is the way to stop being surprised by that.

The primitive types are values that cannot be changed and are compared by content. A string is text in single quotes, double quotes or backticks. A number is a 64-bit floating-point value used for both integers and decimals; it is exact for whole numbers up to Number.MAX_SAFE_INTEGER (2 to the power 53, minus 1), but decimal fractions such as 0.1 cannot be stored exactly, which produces results like 0.1 + 0.2 being 0.30000000000000004. Two special numbers exist: NaN ("not a number", the result of failed arithmetic) and Infinity. A bigint (ES2020), written with an n suffix like 12n, holds integers of any size. A boolean is true or false. undefined is the value of a variable that has not been assigned and of a missing property; null is a deliberate "no value" that a programmer writes on purpose. A symbol is a unique identifier used as a property key; beginners rarely need it.

Everything else is an object: plain objects, arrays, functions, dates, and so on. Objects are compared by identity, so two separately built arrays with the same contents are not equal. The arrays and objects lessons cover them.

The typeof operator returns the type name as a string. It says "function" for functions and "object" for every other object, including arrays (use Array.isArray() to tell) and, because of a bug preserved since the first version of the language, also for null.

Conversions are explicit or implicit. Number(text) turns a string into a number, giving NaN if the whole string is not numeric; parseInt and parseFloat read a number from the start of a string and ignore the rest. String(value) and value.toString() go the other way. Boolean(value) gives false for the six falsy values (0, "", null, undefined, NaN and false itself; 0n too) and true for everything else, including "0" and an empty array. Input from readline() is always a string, so converting it is the first thing most programs do.

Syntax

 JavaScript · syntax
const text = "twelve";          // string
const whole = 12;               // number (integer)
const part = 12.75;             // number (decimal)
const huge = 12345678901234567890n; // bigint
const flag = true;              // boolean
let nothingYet;                 // undefined
const empty = null;             // null, on purpose

typeof value                    // "string", "number", "bigint", "boolean",
                                // "undefined", "object", "function", "symbol"
Number("42")   String(42)   Boolean("")   parseInt("42px", 10)   parseFloat("2.5kg")

Pass 10 as the second argument of parseInt so the string is always read as decimal.

Types at a glance

TypeExample literaltypeof gives
string"harbour""string"
number42, 3.5, NaN, Infinity"number"
bigint9007199254740993n"bigint"
booleantrue"boolean"
undefinedundefined"undefined"
nullnull"object" (quirk)
symbolSymbol("id")"symbol"
object{ a: 1 }, [1, 2]"object"
functionfunction () {}"function"

typeof on each kind of value

One line per type; note the two lines that both say object.

 JavaScript
console.log(typeof "Ferry");
console.log(typeof 42);
console.log(typeof 3.75);
console.log(typeof 9007199254740993n);
console.log(typeof true);
console.log(typeof undefined);
console.log(typeof null);
console.log(typeof { id: 1 });
console.log(typeof [1, 2, 3]);
console.log(typeof function () {});
console.log(Array.isArray([1, 2, 3]), Array.isArray({ id: 1 }));

Output

string
number
number
bigint
boolean
undefined
object
object
object
function
true false

Integers and decimals are both number; there is no separate integer type unless you use a bigint. null reports object even though it is a primitive: the check was wrong in the first JavaScript engine and fixing it would break existing programs, so it stays. Arrays are objects too, which is why Array.isArray() exists. Functions are objects as well, but typeof singles them out as function, which is convenient.

Numbers: precision, safe integers, NaN and bigint

The lines show what floating point can and cannot represent.

 JavaScript
console.log(0.1 + 0.2);
console.log(0.1 + 0.2 === 0.3);
console.log((0.1 + 0.2).toFixed(2));
console.log(Number.MAX_SAFE_INTEGER);
console.log(9007199254740992 + 1);
console.log(9007199254740992n + 1n);
console.log(10 / 0);
console.log("abc" * 2);
console.log(Number.isNaN("abc" * 2));
console.log(Number.isInteger(7.0), Number.isInteger(7.5));

Output

0.30000000000000004
false
0.30
9007199254740991
9007199254740992
9007199254740993n
Infinity
NaN
true
true false

Neither 0.1 nor 0.2 has an exact binary representation, so their sum carries a tiny error and does not equal the stored value of 0.3. toFixed(2) rounds to two decimals and returns a string, which is the right tool for displaying money. Above the safe integer limit, adding 1 to a number can leave it unchanged because the next representable value is two away; a bigint has no such limit. Dividing by zero gives Infinity rather than an error, and arithmetic on text that is not numeric gives NaN. NaN is the only value not equal to itself, so test for it with Number.isNaN().

Converting input between string and number

The input lines are 18 and 2.5. Watch what + does before and after the conversion.

 JavaScript
const line = readline();
console.log(typeof line, line);
const count = Number(line);
console.log(typeof count, count + 1);
console.log(line + 1);
const price = parseFloat(readline());
console.log(price * count);
console.log(String(count) + " boxes");
console.log(Number(""), Number("  7 "), Number("7 boxes"), parseInt("7 boxes", 10));
console.log(Boolean(0), Boolean(""), Boolean("0"), Boolean([]));

Input given to the program: 182.5

Output

string 18
number 19
181
45
18 boxes
0 7 NaN 7
false false true true

readline() gives the string "18"; adding 1 to the string joins the characters, adding 1 to the converted number gives 19. Number() accepts surrounding spaces and treats an empty string as 0, but refuses a string with trailing text, returning NaN; parseInt stops at the first character that is not a digit and returns 7. The last line shows the boolean conversion: the number 0 and the empty string are falsy, but the string "0" and an empty array are truthy, because any non-empty string and any object count as true.

Common mistakes

  • Doing arithmetic on input without converting it

    Why it goes wrong: Everything read from input is a string, so readline() + 5 concatenates. Comparisons like "10" < "9" are also done character by character on strings, which gives true.

    Fix: Convert with Number() (or parseInt/parseFloat) as soon as you read a value that is meant to be numeric.

     JavaScript · fix
    const qty = Number(readline());
    console.log(qty + 5);
  • Comparing decimals with ===

    Why it goes wrong: 0.1 + 0.2 === 0.3 is false because of floating-point rounding, so a comparison that should pass fails for no visible reason.

    Fix: Compare with a tolerance: Math.abs(a - b) < 1e-9, or work in whole units such as cents.

     JavaScript · fix
    const a = 0.1 + 0.2;
    console.log(Math.abs(a - 0.3) < 1e-9); // true
  • Using typeof to test for an object

    Why it goes wrong: typeof value === "object" is also true for null, so code that then reads value.name throws TypeError: Cannot read properties of null.

    Fix: Check for null as well: value !== null && typeof value === "object". For arrays, use Array.isArray(value).

  • Testing for NaN with ===

    Why it goes wrong: NaN === NaN is false, so if (result === NaN) can never be true.

    Fix: Use Number.isNaN(result). The older global isNaN() first converts its argument, so isNaN("abc") is true even though "abc" is a string; Number.isNaN only reports genuine NaN values.

Where you use this

Reading and validating input is where types matter most. A program that reads a quantity must convert it, and a robust one checks the result before using it: if Number(line) gives NaN, the line was not a number and the program should say so rather than print NaN in its answer. The same thinking applies to data from a web form or a file, which always arrives as text. Knowing which values are falsy also lets you write short checks such as if (name) for "a non-empty name was given", as long as you remember that 0 is falsy too and use an explicit comparison when zero is a valid value.

 JavaScript · in practice
const raw = readline();
const amount = Number(raw);
if (raw.trim() === "" || Number.isNaN(amount)) {
  console.log("not a number: " + raw);
} else {
  console.log(amount * 2);
}

Key points

  • Seven primitives: string, number, bigint, boolean, undefined, null, symbol; everything else is an object.
  • One number type for integers and decimals; whole numbers are exact only up to 2^53 - 1.
  • 0.1 + 0.2 is not exactly 0.3; round for display with toFixed() and compare with a tolerance.
  • typeof null is "object" and typeof [] is "object"; use Array.isArray() for arrays.
  • Input is always a string; convert with Number(), parseInt() or parseFloat().
  • Falsy values: 0, 0n, "", null, undefined, NaN, false. Everything else is truthy.

Try it yourself

The starter prints the input text twice, joined. Convert raw to a number so the program prints the doubled quantity, then print the typeof of the original value and of the converted value on one line, separated by a space.

Your program
const raw = readline();
// convert raw to a number, then print the doubled value and the two types
console.log(raw + raw);
Input the program receives: 21
Expected output: 42 string number

Practise this

Exercises for this lesson are in the JavaScript practice set.

Open the JavaScript playground

Frequently asked questions

Why is typeof null "object" in JavaScript?

In the first JavaScript engine, values carried a small type tag, and the tag for objects happened to be the same as the representation of null. typeof read the tag and answered "object". By the time the mistake was noticed, programs depended on it, and a proposal to change the result was rejected because it would break existing websites. Test for null with value === null.

What is the difference between undefined and null?

undefined is what JavaScript itself uses for "no value has been given": an unassigned variable, a missing object property, a missing function argument, or the result of a function with no return. null is a value a programmer assigns deliberately to say "empty on purpose". They are equal under == but not under ===, and typeof reports them differently.

How do I check whether a string is a valid number?

Convert it with Number() and test the result with Number.isNaN(). Also reject an empty or whitespace-only string, because Number("") returns 0 rather than NaN. Avoid the older global isNaN(), which converts non-numeric strings first and so reports true for any text.

Progress is stored only in this browser.

How this page was checked. Every program on it was run with Node.js 22 at build time; runs in your browser in an isolated Web Worker by the publishing checks, and the output shown is what it printed. The Run buttons execute the same code on your device; nothing you type is sent anywhere.