What operator precedence is
When an expression has more than one operator, TypeScript has to decide which one to apply first. The rules for that decision are called operator precedence. They are the same rules you know from school arithmetic: in 1 + 2 * 3, the multiplication is done before the addition.
console.log(1 + 2 * 3); // 7
TypeScript calculates 2 * 3 first, which is 6, and then 1 + 6, which is 7. Reading left to right and adding first would give 9, so knowing the rules matters.
The order, from first to last
- Parentheses
( )are always evaluated first. - Exponentiation
**. - Multiplication, division and remainder
*,/and%, all at the same level. - Addition and subtraction
+and-, at the same level.
When operators sit at the same level, TypeScript goes from left to right. The one exception is **, which goes from right to left.
Examples
console.log(6 - 4 / 2); // 4 (4 / 2 first, then 6 - 2)
console.log(5 * 4 - 2 / 2); // 19 (20 - 1)
console.log(6 / 4 * 3 + 5); // 9.5 (1.5 * 3 + 5)
console.log(10 - 4 - 3); // 3 ((10 - 4) - 3)
console.log(2 ** 3 ** 2); // 512 (2 ** 9, right to left)
In 6 / 4 * 3 + 5, division and multiplication share a level, so the division runs first because it is on the left: 6 / 4 is 1.5, times 3 is 4.5, plus 5 is 9.5.
Using parentheses
Parentheses override every other rule, because whatever is inside them is calculated first:
console.log((1 + 2) * 3); // 9
console.log((6 - 4) / 2); // 1
console.log(5 * (4 - 2) / 2); // 5
console.log(6 / ((4 + 2) / 3)); // 3
The last example nests parentheses. Evaluation starts from the innermost pair: (4 + 2) is 6, then 6 / 3 is 2, then 6 / 2 is 3. You can also use parentheses where they are not needed, to make an expression easier to read. (price * discount) / 100 and price * discount / 100 are the same expression.
Exponentiation and the minus sign
There is one place where TypeScript refuses to guess. A minus sign directly in front of the base of **, as in -2 ** 2, is a syntax error, because it could mean (-2) ** 2 (which is 4) or -(2 ** 2) (which is -4). You write the parentheses yourself.
Working through a longer expression
For a long expression, rewrite it one step at a time, always doing the highest-precedence operation first. Take 4 + 6 % 4 * 2 - 3 ** 2:
- The power goes first:
3 ** 2is 9, which leaves4 + 6 % 4 * 2 - 9. - Remainder and multiplication share a level, so go left to right.
6 % 4is 2, giving4 + 2 * 2 - 9, and then2 * 2is 4, giving4 + 4 - 9. - Addition and subtraction go left to right:
4 + 4is 8, and8 - 9is -1.
Running it prints -1, as the steps predict.
The exercise
The starter code is a single line:
console.log(2 + 3 * 3);
It prints 11, because the multiplication runs first: 3 times 3 is 9, and 2 plus 9 is 11. The goal is to make it print 15 by changing only the order of evaluation.
- Find the target. To get 15 from a product with 3, the other factor must be 5, which is exactly
2 + 3. - Wrap the addition in parentheses so it runs first.
- Keep the rest. The multiplication by 3 stays outside.
console.log((2 + 3) * 3);
Now TypeScript computes 2 + 3 as 5, then 5 * 3 as 15, and prints 15.
If you are ever unsure how an expression will be read, run it with console.log and compare the output with your hand calculation. The two should agree before you move on to larger programs.
Common mistakes
- Assuming left to right everywhere. That is only true among operators at the same level.
2 + 3 * 3is not read from left to right. - Parentheses in the wrong place.
2 + (3 * 3)is the original expression with redundant parentheses, and it still prints 11.(2 + 3 * 3)also prints 11. - Misreading chained division.
8 / 4 / 2is 1, while8 / (4 / 2)is 4. - Mixing up the levels of
**and*.2 * 3 ** 2is 18, because the power runs first.(2 * 3) ** 2is 36.
Key takeaways
- Order: parentheses, then
**, then* / %, then+ -. - Operators at the same level go left to right, except
**. - When in doubt, add parentheses. They never hurt, and they show what you mean.