Module 1 · First Programs: The Console, let and const, Types, typeof
typeof, undefined and null: Asking a Value What It Is
In this lesson
- Use
typeofon every kind of value and read its answers, including the two that surprise. - Name the three everyday sources of
undefined, and say who puts anullin place. - Tell a name that was never declared from one that holds
undefined, and check for each without a crash.
David's shop sends a greeting with every receipt. One morning the receipt says Hello, undefined where the customer's name should be. Nothing crashed, nothing warned him, and the word looks like a bug in the printer. It is not. It is a value, printed faithfully, and this lesson follows it back to the line that should have set it.
typeof: ask a value what it is
Lesson 03 used typeof in passing. It is an operator, like -, that goes in front of one value and gives back the name of its type, as a string.
The typeof operator
typeof value
typeofis a keyword that works as an operator; it needs no brackets.valueis any expression: a literal, a name, a sum.- The result is always a string, such as
"number"or"string", so you can print it or compare it.
Here is the one program that asks twelve values, one of every kind you will meet in this track.
console.log(typeof 42);
console.log(typeof 3.14);
console.log(typeof NaN);
console.log(typeof "hi");
console.log(typeof "");
console.log(typeof true);
console.log(typeof undefined);
console.log(typeof null);
console.log(typeof 10n);
console.log(typeof Symbol("id"));
console.log(typeof { name: "Zara" });
console.log(typeof console.log);
number
number
number
string
string
boolean
undefined
object
bigint
symbol
object
function
The same answers, as a table you can keep:
| The value | typeof says | Is that the type from lesson 03? |
|---|---|---|
42, 3.14, NaN, Infinity | "number" | yes |
"hi", "" | "string" | yes |
true, false | "boolean" | yes |
undefined | "undefined" | yes |
null | "object" | no: the type is null |
10n | "bigint" | yes |
Symbol("id") | "symbol" | yes |
{ name: "Zara" }, [1, 2] | "object" | yes |
console.log, any function | "function" | no: a function is an object |
So typeof gives a type's name as a string, and seven of its answers match lesson 03's table exactly.
The two answers that surprise
typeof null is "object", and that is a bug. The first JavaScript engine, written at Netscape in 1995, stored a small type tag beside each value. The tag for objects was 0, and null was stored as the zero pointer. So the check read null as an object. By the time anyone wanted to fix it, millions of pages depended on the old answer. A fix was proposed for ES2015 and dropped for that reason. So the bug is now part of the standard, and it will stay.
typeof a function is "function". A function is a kind of object, so by the table the answer should be "object". The language makes an exception on purpose, because "can I call this?" is a question programs need to ask. This one is a feature, not a bug.
So typeof cannot spot a null, and it can spot a function. The section "Checking for each kind of nothing" shows the right test for null.
Where undefined comes from
undefined means "no value yet". You rarely write it. The engine puts it there in three everyday places, and David's bug came from the first.
let customerName;
console.log("Hello,", customerName);
function greet(name) {
console.log("Hello,", name);
}
greet();
const customer = { name: "David" };
console.log(customer.phone);
Hello, undefined
Hello, undefined
undefined
- A name declared with no value.
let customerName;makes the name and putsundefinedin it. David meant to fill it from the order and never did. - A missing argument.
greetis a function that expects aname(Module 5 teaches functions). Called with nothing in its brackets, itsnameholdsundefined. - A missing property.
customeris an object with anameand nothing else (Module 8). Asking forcustomer.phonegivesundefined, not an error.
So when undefined shows up, ask three questions. Was the name ever given a value? Was an argument left out? Is that property really there?
null: no value, on purpose
The engine never fills a name with null by default, the way it fills one with undefined. A null is always somebody's choice: yours, whoever wrote the data your code received, or a built-in tool that answers "found nothing" with it. It says "this was checked, and there is nothing".
const form = { name: "Amara", middleName: null };
console.log(form.middleName);
console.log(form.nickname);
console.log(typeof form.middleName);
console.log(typeof form.nickname);
null
undefined
object
undefined
The form asked Amara for a middle name, and she has none: null. It never asked for a nickname: undefined. Both mean "nothing", but they answer different questions. And typeof says "object" for the null, the bug from the section above. So null is always somebody's decision, and that is what makes it useful to read.
Checking for each kind of nothing
To ask "is this undefined?" or "is this null?", compare with ===. Lesson 03 used it to compare two numbers, and it works the same on these two values.
let phone;
const middleName = null;
console.log(phone === undefined);
console.log(middleName === null);
console.log(typeof middleName === "object");
console.log(typeof phone === "undefined");
true
true
true
true
The third line is true, but it is no test for null: every object gives "object" too. So test null with === null, and undefined with === undefined.
A program usually wants to act on the answer, not print true. That is a job for if, which Module 4 teaches. Here is its shape, to read now and use as given: the first test that is true picks the block that runs.
const value = null;
if (value === undefined) {
console.log("missing");
} else if (value === null) {
console.log("empty");
} else {
console.log("value:", value);
}
empty
So === undefined and === null are the two exact tests, and if lets a program choose what to do with them.
A name that was never declared
There is a third kind of missing: a name nobody ever declared. Reading it stops the program, as lesson 02 showed. Asking typeof about it does not.
console.log(typeof discountCode);
console.log(typeof window);
console.log(typeof process);
undefined
undefined
object
discountCode was never declared, and typeof answers "undefined" instead of throwing. Remove the typeof, and the same line stops the program with ReferenceError: discountCode is not defined.
The next two lines show why that matters. window is the browser's global object, and process is Node's. This program ran in Node 22, so window does not exist and process does. A library that must run in both places asks typeof window first. So typeof is the one safe way to ask about a name that may not exist.
The smallest use: store a value, ask its type, print both.
const temperature = 36.6;
console.log(temperature, "is a", typeof temperature);
36.6 is a number
Change 36.6 to "36.6", with quotes, and the answer becomes string.
David's program declared the name early and planned to fill it later. The fix is to give the name its value where it is made, and to make it a const.
let customerName;
console.log("Before:", typeof customerName);
const fixedName = "Maria";
console.log("Hello,", fixedName);
console.log("After:", typeof fixedName);
Before: undefined
Hello, Maria
After: string
The typeof lines are the trace: undefined before means the name was declared and never set. A const cannot be declared without a value, so this whole bug cannot happen to one.
Zara tests the edges first. Her profile has a name, a null she chose and a property she never added.
const profile = { name: "Zara", school: null };
console.log("name:", profile.name, typeof profile.name);
console.log("school:", profile.school, profile.school === null);
console.log("city:", profile.city, profile.city === undefined);
name: Zara string
school: null true
city: undefined true
Each line pairs a value with the right test for it. school is null because Zara is between schools; city is undefined because nobody asked.
Kenji wants a line per value that says what it holds, the way a form checker would. He uses the if shape from above.
const value = undefined;
if (value === undefined) {
console.log("missing");
} else if (value === null) {
console.log("empty");
} else {
console.log(typeof value);
}
missing
Change the first line to null, 42 and "hi" in turn, and run it each time. You should see empty, number and string.
Where this is used
- lodash. This popular helper library answers
isString(value)with a line that startstypeof value == 'string'. ItsisNiltests fornullandundefinedtogether. - GitHub's REST API. A user profile comes back with every field present. A field the user left blank, such as
bio, comes back asnullrather than missing. That is "checked, and there is none", sent as data (Module 8 reads it). - Next.js. Its code can run on the server or in the browser.
typeof windowis the usual check for which, the one from "A name that was never declared". Its documentation names that check inside rendering logic as a cause of hydration errors, so it belongs elsewhere.
Common mistakes
1. Testing for null with typeof.
const school = null;
console.log(typeof school === "null");
No message: it prints false, every time, for every value. typeof never answers "null". Write school === null. You will try typeof because it answered correctly for every other type.
2. Reading a property of undefined.
let user;
console.log(user.name);
TypeError: Cannot read properties of undefined (reading 'name'). With null in user, the message says null instead. A missing property gives undefined, but asking anything of undefined itself stops the program. This is one of the most common errors in all of JavaScript; Module 8 shows the ?. operator that guards it. You will make it because the name looks set: it was declared, just never given an object.
3. A capital letter in a type name.
const price = 450;
console.log(typeof price === "Number");
No message: false. typeof answers in small letters, "number", and string comparison counts capitals. You will write the capital because type names look like proper nouns.
4. Sums with a value that was never set.
let count;
count = count + 1;
console.log(count);
No message: it prints NaN. undefined + 1 has no sensible answer, and lesson 03 showed that NaN then spreads. Start the count at a value: let count = 0;. You will forget the = 0 because a count obviously starts at zero, to you, and not to the engine.
Amara's form checker looks at five values. For each, print missing if it is undefined, empty if it is null, and the value itself otherwise.
Output. Exactly these five lines.
missing
empty
0
false
Zara
let nickname;
const school = null;
const siblings = 0;
const subscribed = false;
const name = "Zara";
// Use the if shape from "Checking for each kind of nothing", once per value.
// 0 and false are real values, not nothing: they print as themselves.
Not graded. Notice that 0 and false are not "nothing". Module 2 shows an operator that treats them as if they were.
A form field always arrives as text. Alice wants to know whether it holds a number. Read one word from the input, try to turn it into a number with Number(), and print number if that worked or string if it gave NaN.
Input. One word, with no spaces.
Output. number or string.
Sample. Input 42 gives number; input Zara gives string.
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
const word = next();
const asNumber = Number(word);
// Number.isNaN(asNumber) is true when the word did not convert.
// Push "string" in that case, and typeof asNumber otherwise.
console.log(out.join("\n"));
The first six lines read the input for you; lesson 05 explains each one. Type the input into the Playground's stdin box. Not graded on its own: the graded version, type-of-each, also turns true, false, null and undefined into their values.
Common doubts
If
typeof nullis a bug, why not fix it?Old pages check
typeof x === "object"and expectnullto pass. Changing the answer would break them without warning. The web keeps its old behaviour almost always, and this is the most famous case.Should I ever write
undefinedmyself, as inlet x = undefined;?It runs, but it blurs the one useful difference between the two. Write
nullwhen you mean "none", so thatundefinedalways means "never set".Why does
typeofanswer with a string and not something else?A string can be printed, compared with
===and stored. That is all a program needs to do with a type's name.Is
typeofa function, since I can writetypeof(x)?No, it is an operator.
typeof(x)works because the brackets just groupx, the way they group(2 + 3). This track writestypeof x.
Key takeaways
typeof valuegives the type's name as a string, in small letters.- Two answers surprise:
typeof nullis"object", a bug kept since 1995, and a function gives"function". undefinedcomes from a name with no value, a missing argument or a missing property.nullis never the engine's default; someone put it there, and it means "none, on purpose".- Test them with
=== undefinedand=== null;ifacts on the answer. typeofof an undeclared name gives"undefined"; reading the name throws a ReferenceError.
Next, lesson 05 explains the six lines that read the input, so every problem in this track can start.
End of lesson 4
Mark it done, and your progress moves with you.
Next: Reading Input: The Starter Every Problem Uses, Line by Line