Skip to content
Lesson 3 of 15

Step 1 of 5 · Reading · ~4 min

Learn

Getting Started

Numbers and Math

TypeScript has exactly one everyday number type, number, and it behaves like a 64-bit floating-point value. By the end of this lesson you can split a quantity into whole units and a remainder, explain why 0.1 + 0.2 is not 0.3, and turn text into a number without letting bad input slip through.

One type for every number

There is no separate integer type: 3, 3.5 and -0.001 are all number. That surprises people coming from C, Java or Python, because it changes what / means.

const items: number = 17;
const perBox: number = 5;

console.log(items + perBox);   // 22
console.log(items - perBox);   // 12
console.log(items * perBox);   // 85
console.log(items / perBox);   // 3.4   <-- real division, never truncated
console.log(items % perBox);   // 2     (remainder)
console.log(2 ** 10);          // 1024  (exponentiation)

/ never does integer division: 17 / 5 is 3.4, full stop. To get whole boxes you ask for the whole part explicitly, and % gives what is left over:

Math.floor(17 / 5);  // 3: rounds toward negative infinity
Math.trunc(17 / 5);  // 3: chops the decimals (toward zero)
Math.round(17 / 5);  // 3: nearest integer
Math.ceil(17 / 5);   // 4: rounds up
17 % 5;              // 2: so 3 full boxes and 2 left over

Math.floor and Math.trunc agree for positive values and split on negatives: Math.floor(-3.5) is -4, Math.trunc(-3.5) is -3. Also note that % takes the sign of the left operand: -7 % 3 is -1, not 2. Pairing Math.floor(a / b) with a % b is the standard way to split a count into "whole units" and "the rest", but only for non-negative a.

Floats are approximate

console.log(0.1 + 0.2);          // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3);  // false

This is IEEE 754 arithmetic, not a TypeScript bug: 0.1 has no exact binary representation, just as 1/3 has no exact decimal one. Two consequences. Never store money as a number of dollars; store whole cents. And integers are exact only up to Number.MAX_SAFE_INTEGER (2^53 - 1); beyond that use the bigint type, written with an n suffix such as 123n.

Parsing text into numbers

Input arrives as a string, so you convert it, and conversion can quietly go wrong:

Number("42");        // 42
Number("42abc");     // NaN: the whole string must be numeric
Number("2.5");       // 2.5
Number("");          // 0   <-- an empty string becomes ZERO, not NaN
parseInt("42abc", 10); // 42: lenient, reads the leading digits only

NaN ("not a number") is contagious: any arithmetic with it gives NaN, and NaN === NaN is false, so test it with Number.isNaN(x). Number.isInteger(x) is true only for whole numbers and is false for NaN, 2.5 and Infinity.

The Number("") result is the trap. A blank field is not zero, so checking only isInteger accepts a blank line as 0. Validate the text too. || means "or" and ! means "not"; the conditionals lesson covers both. The expression below is true when the input must be rejected:

const field: string = "  ";
const quantity: number = Number(field.trim());
console.log(field.trim() === "" || !Number.isInteger(quantity));   // true: a blank field is rejected

Common mistakes

  • Printing the raw quotient. 100 / 60 is 1.6666666666666667, not 1. Whole units need Math.floor.
  • Using % on negative numbers and expecting a modulus. -1 % 60 is -1, not 59.
  • Trusting Number(""). It is 0, so a blank line passes an isInteger check unless you test the text as well.
  • Comparing floats with ===. Compare whole cents instead, or allow a small tolerance.

Your exercise

Split a count of minutes into days, hours and minutes. The starter trims the line into text and converts it into the number minutes; the input is always a valid non-negative whole number, so no validation is needed here.

Work from the biggest unit down, using the pairing from the first section: Math.floor with / gives the whole units, and % gives what is left over. Do it twice: once to peel off the days, then again on the leftover to split it into hours and minutes. Keep each step in a named const so every line does one thing, then print the three parts with a template literal.

The mistakes the hidden tests catch are printing the raw quotient (for example 1.5 hours) and computing the hours from all the minutes instead of from what is left after the days are removed.

Up nextStringsStrings and Interfaces

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…