Before you begin
Why this matters
Many early surprises come from a value of one type being treated as another: a number that is really text, or a comparison that puts "10" before "9". Once you know each value’s type, you can predict what an operation will do with it.
What this helps you reason about
- Predict what + gives for two numbers, for two pieces of text, and for one of each.
- Explain why "10" < "9" is true.
- Spot a number that arrived as text before it is added to anything.
Every program works with values: the number 3, true or false, the text "pear". This lesson shows the kinds of value TypeScript has, and how a value’s type decides what + and < do with it.
Already know this? The short version
- The basic value types are number, string, and boolean (plus bigint, symbol, undefined, and null). Every number is a 64-bit floating-point value, so 7 / 2 is 3.5 and 7.0 is the same value as 7.
- + adds two numbers but joins text when either side is a string, so "5" + 2 is "52"; TypeScript rejects -, *, and / on a string, which plain JavaScript would convert.
- < on two strings compares character codes from left to right, so "10" < "9" and "Zebra" < "apple" are both true.
- Convert text to a number with Number(text) before arithmetic; Math.trunc, Math.floor, and Math.round give whole numbers.
Words in this lesson (6)
- value
- One piece of data that a program works with, such as the number 3, true or false, or the text "pear". Every value has a type.
- type
- The kind of a value, such as number, string, or boolean. It decides which operations TypeScript allows on the value.
- string
- A value that holds text: a sequence of characters, written between quotes, such as "pear".
- boolean
- A value that is either true or false. A comparison such as 12 < 20 gives a boolean.
- floating-point number
- A number stored in binary, with about 16 significant decimal digits. Most decimal fractions, such as 0.1, are stored as the nearest binary value, not exactly.
- compiler
- A program that checks your code and translates it into another form. The TypeScript compiler checks types, then removes them and produces plain JavaScript.
Examples are focused snippets; imports, enclosing functions, or classes may be omitted. C examples use C11; Haskell examples use Haskell 2010. Expand the notes for language-specific depth.
01 / Values
What is a value?
A value is one piece of data that a program works with. 3 is a value. So is true, and so is the text "pear". A program computes new values from old ones: 3 * 4 gives the value 12.
Every value has a type: the kind of data it is. 3 and 12 have the type number. "pear", written between quotes, is a string: a value that holds text. true and false are the two values of the type boolean. A comparison such as 12 < 20 gives a boolean.
In the program below, const price = 3 gives the name price to the value 3, so later lines can use it. Variables, the next lesson, explains names in detail.
const price = 3;
const boxes = 4;
const total = price * boxes; // 12
const cheap = total < 20; // true
const fruit = "pear";
console.log(fruit, total, cheap); // pear 12 true Every value has a type: 12 is a number, true is a boolean, and "pear" is a string.
Precisely: all the kinds of value
JavaScript has eight kinds of value: number, string, boolean, bigint, symbol, undefined, null, and object. TypeScript adds types that are checked before the program runs and then removed; the values themselves are JavaScript’s.
Experiment
Watch a comparison give true or false
price * boxes computes a new number from two numbers. total < 20 compares two numbers and gives a boolean: true when the comparison holds, false when it does not.
Why it matters A comparison is an operation like any other: it computes a value, and that value has a type of its own.
Predict what cheap holds. Then change const boxes = 4; to const boxes = 8; and predict again.
const price = 3;
const boxes = 4;
const total = price * boxes;
const cheap = total < 20;
const fruit = "pear";
console.log(fruit, total, cheap);
What to look for
Step past each line. Each new name appears in the panel with its value: price 3, boxes 4, total 12, cheap true, and fruit "pear", in quotes because it is a string. The run prints pear 12 true. After the edit, total shows 24, cheap shows false, and the run prints pear 24 false. <top level> is the stepper’s name for the code outside every function. Step can stop more than once on the same line, as it does on the last line here. That is normal for the debugger, the tool that pauses the program at each stop.
Expected output
pear 12 true02 / Types
What does a type decide?
A value’s type decides which operations make sense for it, and what each operation does. The same symbol can mean different things for different types.
For two numbers, + adds: 5 + 2 is 7. For two strings, + joins the text: "5" + "2" is "52". < compares two numbers by size, and two strings in alphabetical order: "apple" < "banana" is true.
Booleans have their own operations. && (“and”) gives true when both sides are true. || (“or”) gives true when at least one side is true. ! (“not”) turns true into false and false into true.
Some operations make no sense for a type, such as multiplying text. The TypeScript compiler, the program that checks your code and translates it into JavaScript before it runs, rejects "pear" * 2.
console.log(5 + 2); // 7
console.log("5" + "2"); // 52
console.log("apple" < "banana"); // true
console.log(true && false); // false
console.log(!false); // true The types of the values decide what an operation does: + adds numbers and joins strings.
Coming from Python: and, or, and not are written &&, ||, and !.
03 / Numbers
Are whole numbers and fractions different types?
Many languages have two kinds of number. Integers are whole numbers, such as 7 or -2. Floating-point numbers can have a fraction, such as 3.5. TypeScript has one type, number, for both: every number is a floating-point number. So 7 and 7.0 are the same value, and 7 / 2 is 3.5. In the code below, 7.0 === 7 is true: === asks whether two values are equal and gives a boolean. A single = does something else: it gives a name a value.
When you need a whole number, ask for one. Math.trunc(x) cuts off the fraction. Math.floor(x) rounds down to the whole number below. Math.round(x) rounds to the nearest whole number, and a value exactly halfway, such as 2.5, goes up to 3.
A floating-point number is stored in binary, the base-2 form the computer uses for numbers. Most decimal fractions, such as 0.1, have no exact binary form, so they are stored as a very close value. Equality and comparison shows what that means when you compare two results. That is why 0.1 + 0.2 prints 0.30000000000000004. Two later topics in the catalog go further: Integers, signs, and overflow, and Floating-point numbers.
console.log(7 / 2); // 3.5
console.log(7.0 === 7); // true
console.log(Math.trunc(7 / 2)); // 3
console.log(Math.round(2.5)); // 3
console.log(0.1 + 0.2); // 0.30000000000000004 In TypeScript every number is a floating-point number: 7 / 2 is 3.5.
Coming from Java or C: There is no integer division: 7 / 2 is 3.5, and Math.trunc(7 / 2) gives 3.
Precisely: safe integers and bigint
A number holds every whole number exactly up to 2^53 - 1, which is Number.MAX_SAFE_INTEGER. For larger whole numbers, use bigint, written with an n: 9007199254740993n. A bigint and a number cannot be mixed in one arithmetic operation.
Experiment
Divide 7 by 2, then ask for a whole number
Every TypeScript number is a floating-point number, so 7 / 2 keeps its fraction. Math.trunc cuts the fraction off and gives 3. Writing 7.0 does not make a different kind of number.
Why it matters In TypeScript, a division keeps its fraction. Ask for a whole number with Math.trunc or Math.floor.
Predict each and whole. Then change the first line to const each = 7.0 / 2; and predict again.
const each = 7 / 2;
const whole = Math.trunc(7 / 2);
console.log(each, whole);
What to look for
Step past each line. each shows 3.5 and whole shows 3, and the run prints 3.5 3. After the edit nothing changes: each still shows 3.5, because 7.0 and 7 are the same number.
Expected output
3.5 304 / Text
What is text made of?
A string is a sequence of characters: letters, digits, spaces, and symbols, one after another. "pear" has four characters. fruit.length gives the number of characters, and fruit[0] gives the first one. Positions start at 0. TypeScript has no separate type for one character: fruit[0] is a string of length 1.
Each character is stored as a number, its character code. "A" has the code 65, "B" 66, and so on, and "a" has 97. The digits "0" to "9" have the codes 48 to 57. fruit.charCodeAt(0) gives the code of the first character.
< on two strings compares them character by character, by code. That is why "10" < "9" is true: the first characters are "1" (code 49) and "9" (code 57), and the rest does not matter. It is also why "Zebra" < "apple": every capital letter has a smaller code than every small letter.
const fruit = "pear";
console.log(fruit.length); // 4
console.log(fruit[0]); // p
console.log(fruit.charCodeAt(0)); // 112
console.log("10" < "9"); // true A string is a sequence of characters, and each character is stored as a number.
Precisely: UTF-16 and localeCompare
A JavaScript string is a sequence of UTF-16 code units, and length counts those units, not the characters a reader sees: "🍐" has length 2. a.localeCompare(b) compares text the way a dictionary for a given language does, so "apple" comes before "Zebra".
05 / Mismatches
What happens when the types do not match?
When the two sides of an operation have different types, a language must decide what to do: convert one side, or refuse.
For +, JavaScript converts. If either side is a string, + turns the other side into text and joins the two. So "5" + 2 is "52", not 7. TypeScript allows this, because joining text and a number is often what you want, as in "boxes: " + 4.
The trap is a number that arrives as text, such as what someone typed into a form. Convert it first with Number(text): Number("5") + 2 is 7.
For -, *, and /, TypeScript refuses. "5" * 2 is rejected with: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
console.log("5" + 2); // 52
console.log(Number("5") + 2); // 7
console.log("boxes: " + 4); // boxes: 4 If either side of + is a string, + joins text. Convert typed numbers with Number first.
Coming from Python: Python refuses "5" + 2 with a TypeError; JavaScript joins it into "52" with no error at all.
Precisely: what JavaScript does on its own
Plain JavaScript converts for -, *, and / too, in the other direction: "5" * 2 is 10 and "5" - 2 is 3. TypeScript rejects these lines before they run. Number("pear") gives NaN, “not a number”, and Number("") gives 0, so check text before you convert it.
Experiment
Add a number to a string
apples is a string, so + turns pears into the text "2" and joins the two strings. Number(apples) first turns the text "5" into the number 5, so + adds two numbers.
Why it matters Text that looks like a number is still text. Convert it before you calculate with it.
Predict what fruit holds. Then change apples + pears to Number(apples) + pears and predict again.
const apples = "5";
const pears = 2;
const fruit = apples + pears;
console.log(fruit);
What to look for
Step past each line. apples shows "5" in quotes: it is a string, not a number. fruit shows "52", also a string, and the run prints 52. After the edit, fruit shows 7 without quotes, a number, and the run prints 7.
Expected output
5206 / Try it
Can you explain a fresh example?
Decide the type of each value first, then what each operation does with it. The next lesson, Variables, looks at the names that hold values.
const crates = "3";
const more = 4;
console.log(crates + more, Number(crates) + more, "10" < "9");
What is printed?
Reveal the reasoning
34 7 true. crates holds a string, so crates + more joins text. Number(crates) is the number 3, so the second + adds. "10" < "9" compares the characters "1" and "9" by their codes, and "1" comes first.
Practice tickets
- VALUE-101 · An order of 3 cake boxes plus 2 extra shows 32 boxes → Free
- VALUE-102 · Stall B4 appears as stall 62 on the market map → Sign in · Pro
- VALUE-103 · Weighed cheese gets labels that are too cheap → Sign in · Pro