Before variables, functions, or objects can make sense, we need to know what kinds of things
JavaScript actually deals in — and where the tool for asking "what kind of thing is this"
quietly lies to you.
What this lab produces: no files, no commit — a pure concept lab. You'll run
one short snippet in a console or with node.
Concept type: Common Concept, JavaScript-Specific Rules
◇
VALUES & TYPES1 of 10
Every language needs some way to represent and tell apart different kinds of information.
This lab is JavaScript's answer.
Mental Models
Mental Model 1 of 5The Value Carries the Type
The type belongs to the value sitting in memory, not to the variable name pointing at it. A variable is just a label.
Mental Model 2 of 5typeof Follows the Arrow
Renaming a variable, or copying its value into ten other variables, never changes what typeof reports — it's always reading the value at the end of the arrow.
Mental Model 3 of 5Two Families, Not One
Seven specific primitive kinds, then everything else — arrays, functions, plain objects, dates — all counted as "object." Lab 21 covers why this split matters.
Mental Model 4 of 5An Analogy: The Stamp Is on the Package
Think of a value like a package with its material stamped directly on it — glass, plastic, wood. The shipping label (your variable name) is just paper stuck to the outside; you can peel it off, stick a new one on, or put ten labels on ten different packages — none of that changes what the package underneath is actually made of.
Mental Model 5 of 5Misconception: typeof Doesn't Read Your Code
It's tempting to think typeof someVariable somehow inspects how you wrote the code. It doesn't — it inspects whatever value that expression evaluates to at the exact moment it runs. The same line of code can report a different type at 9am than it does at 9:01am, if the value changed in between.
Learning Objectives
Objective 1 of 4 — I can name all seven JavaScript primitive types and explain what falls under the single "object" catch-all instead.
Objective 2 of 4 — I can explain why a JavaScript variable's type can change over its lifetime, and how that's different from a statically-typed language.
Objective 3 of 4 — I can predict what typeof returns for a given value — including the null and function special cases — and explain why each behaves that way, not just recite the answer.
Objective 4 of 4 — I can write a "is this actually a usable object" check that isn't fooled by typeof null === "object".
Pre-Lab Quiz
Answer from intuition first. This lab has a well-known trick question in it on purpose.
Question 1 of 5Once a variable is assigned a number, can that same variable later hold a string instead?Open question
Question 2 of 5Guess: what does typeof null return?Open question
Question 3 of 5Is a function value a fundamentally different type from a plain object, or a special case of one?Open question
Question 4 of 5let x = 5; then later x = "hello"; — does that second line cause any kind of type error?Open question
Question 5 of 5Guess: does typeof give arrays their own result, separate from plain objects?Open question
The Concept
"Type" is not a JavaScript invention
A type is simply a category that tells you what kind of thing a piece of
data is, and therefore what you're allowed to do with it — you can add two numbers, but
adding two booleans (true/false values) doesn't mean the same thing conceptually.
Every mainstream programming language needs some notion of type for exactly this reason:
without it, the language (or you) would have no way to know whether an operation on a
piece of data even makes sense.
What's JavaScript-specific is which types exist, how loosely they're enforced,
and what the built-in typeofoperator — a small piece of
syntax, like + or -, that takes a value and produces a result,
in this case a string naming that value's type — will and won't tell you correctly about
them.
Cross-language note
Common concept: every value has a type.
Python: has separate int and float types, plus
str, bool, NoneType, and checks types with
type()/isinstance().
JavaScript: has exactly one numeric type, number, for both
whole and decimal values (Lab 34 covers the precision consequences of that), and checks
types with the typeof operator — which, as Question 2 above showed, has at
least one well-known bug baked in.
Seven primitives, one catch-all
JavaScript has exactly seven primitive types. "Primitive" here just means
a value the language treats as a single, indivisible piece of data — you can't reach
"inside" it to change a piece of it; any change produces a brand-new value instead. The
seven are: string (text), number (both whole and decimal
numbers), boolean (true/false), undefined
and null (two different flavors of "nothing" — Lab 04 is entirely about that
distinction), symbol (a guaranteed-unique value, used as a rare kind of
identifier), and bigint (whole numbers too large for the regular
number type to represent precisely).
Everything else in the language — plain {} objects, arrays, functions, dates,
and anything else you can build with new or a literal — falls under one
single, broad type: object. That split (the third mental-model diagram above)
matters a lot more once we get to how values are copied and compared (Lab 21), but for now
it's just the map of what exists.
Why does a typeof operator even need to exist?
In a statically-typed language, the compiler already knows every variable's type before
the program ever runs, so it can catch a type mistake ahead of time and refuse to compile.
JavaScript has no such compile-time check — a variable's type is only knowable by looking
at whatever value it currently holds, while the program is running. That's exactly
the gap typeof fills: it's a way for your running code to ask, at that exact
moment, "what kind of thing am I holding right now?" and branch accordingly. Without it,
code that needs to behave differently for a string versus a number would have no reliable
way to tell them apart at all.
function describe(value) {
if (typeof value === "string") {
return "a piece of text";
}
if (typeof value === "number") {
return "a number";
}
return "something else";
}
What typeof actually checks, and where it's wrong
typeof value reports a string naming the value's type — but it has two
long-standing quirks worth knowing up front, not stumbling into later:
typeof null returns "object", not "null". This is
a bug from the language's original 1995 implementation that was never fixed, because fixing
it would break existing code across the web. It does not mean null behaves like
an object — trying to read a property off null throws an error immediately.
typeof a function returns "function", even though a function
is, underneath, an object (something Lab 11 covers directly). It's a convenience label, not
evidence of a separate fundamental type.
The practical consequence of quirk #1: a check like typeof x === "object",
meant to mean "x is a real object I can use," will also silently match x = null
— which is not something you can actually use like an object. The safe version adds an
explicit exclusion: typeof x === "object" && x !== null.
Lab
Primary objective: predict what typeof reports for a spread of values, including the two quirky ones above.
You'll need: a browser console or node — no project, no files.
Lab 1 of 1 — Probe typeof across a spread of values
Task
Predict, then check, what typeof reports for nine different values.
Instructions
Step 1 of 4
// Paste this into a scratch file or console. Read it — do not run it yet.
This step is complete when: you've written down a guess for all nine lines, including the two you think might be surprising.
Step 2 of 4
Write your nine predictions, then reveal.
Output, in order:
"string"
"number"
"boolean"
"undefined"
"object" <- the quirk: null is not actually an object
"symbol"
"bigint"
"object"
"function" <- functions get their own label, but are objects underneath
What you wrote: nine typeof calls across every primitive type plus
two object-family values.
What the engine effectively does: for seven of these it reports the
exact primitive type by name. For null, it reports the type tag left
over from the original 1995 implementation instead of the correct
answer. For the function, it recognizes the value is callable and
reports that specifically, rather than the more general "object".
This step is complete when: you've run the snippet yourself and it matches the revealed output.
Step 3 of 4
// Edit the file yourself. Don't paste finished code — type it from these comments.
// Add one more console.log(typeof ...) call, checking an
// array literal, e.g. [1, 2, 3].
// Add a second one checking new Date().
This step is complete when: both new lines are added to your file, after the existing nine.
Step 4 of 4
Predict what both new lines report, then run and compare — then answer this comprehension check before moving on: given typeof [1, 2, 3], why doesn't typeof have a separate "array" result the way it has a separate "function" result?
Comprehension Checklist
I can name all seven primitive types without looking them up.
I can explain why typeof null === "object" without calling it "just how JavaScript works" — I know it's a historical bug, not a rule to reason from.
I know a function is a type of object, not a separate fundamental type, even though typeof labels it specially.
I know typeof tells me about the current value, not the variable — the same variable name can hold different types over its life.
I can write typeof x === "object" && x !== null from memory as the safe version of an object check.
Post-Lab Quiz
These are different questions from the pre-lab quiz — they test what the experiment should
have taught you, not the same questions again.
Question 1 of 5What does typeof [1, 2, 3] return?Open question
Question 2 of 5You want to check that a value is a real, usable object — not null. Which check is correct?Open question
Question 3 of 5let value = someCondition ? 42 : "42"; — before running this, can you say for certain what typeof value will be, just by reading the source code?Open question
Question 4 of 5Which of these does typeof NOT report as "object": {}, [], null, function(){}?Open question
Question 5 of 5let x = "hello"; then x = 100; — what does typeof x report now, and what would it have reported right before the reassignment?Open question
Reflection Questions
Write your own answer first — the blurred text is one possible answer, not the only correct one.
Reflection 1 of 3. If you've used a language with fixed variable types before, what's the biggest adjustment in reasoning this "type belongs to the value, not the variable" model requires?
Mostly a shift from "this variable is a number" to "this variable currently points at a
number." In a fixed-type language the compiler rules out ever assigning a string to it;
in JavaScript nothing stops that reassignment, so bugs where a variable unexpectedly
holds the "wrong" type show up at runtime instead of being caught ahead of time.
Reflection 2 of 3. Now that you know typeof null is wrong, where might you have previously trusted it without noticing?
Any spot using typeof x === "object" as a stand-in for "x is a real object I
can access properties on" — a check like that silently also passes for
x = null, which then throws the moment you try x.someProperty.
The safe version checks x !== null as well, or checks truthiness first.
Reflection 3 of 3. In your own words, explain to an imaginary coworker why "typeof reads the code" is wrong and "typeof reads the live value" is right. What's a one-sentence example that proves it?
Something like: "if the exact same typeof x line runs twice, once before
x is reassigned and once after, it can report two completely different
answers — proof that it's inspecting the value at that moment, not anything about how
the line itself is written."
What Breaks If This Understanding Is Wrong?
If you think a variable "is a number" rather than "currently holds a number," reassignment
bugs will look mysterious. And if you don't know typeof null === "object" is a
bug, you'll eventually write a null-check using typeof x === "object" that
silently also matches null — a classic, hard-to-spot source of crashes.
What JavaScript Concept Was Learned Today?
JavaScript's eight types (seven primitives plus object), and where the
built-in typeof operator can and can't be trusted.
Relates to: ◇ Values & Types (1 of 10) — this experiment demonstrated
JavaScript's specific answer to "how does the language represent and distinguish kinds of
information."
Next
Lab 04 zooms in on one specific corner of this type system: the different ways JavaScript
represents "nothing." You now know undefined and null are two of
the eight types from today — next we'll see exactly how they differ from each other, and
from a name that was never declared at all.