Skip to content

Exercise 4 of 10 · Types

The Ticket Machine

What you will make

A bus ticket summary that adds up the riders and works out the fare, once you have fixed the one value the compiler refused to accept.

The one new idea: a type annotation such as : number says what a name must hold, and a value that does not match stops the program before it runs

A number stored as text is a common bug in real code, and it rarely crashes: it quietly turns 2 plus 3 into 23. A type annotation writes down what a value is meant to be, and the compiler holds every line to it before the program is allowed to run.

Go straight to the code ↓

Saying what a name is for

In the last three exercises the compiler worked out the type of each name by itself, from the value you gave it: const eggs = 45 holds a number, and const owner = "Sam" holds a string, which is TypeScript's word for text.

You can also write the type down yourself:

TypeScript
const route: string = "Harbour Loop";
const stops: number = 6;

console.log(route, "has", stops, "stops");
Output
Harbour Loop has 6 stops

The colon and the word after the name are a type annotation. : string says this name holds text, and : number says it holds a number. Both are written in small letters.

Why write down something the compiler could work out? Because an annotation says what the value is meant to be, and that is the one thing the compiler cannot guess. When the value you typed and the type you promised disagree, the compiler takes the promise as the truth and flags the value.

The bug an annotation catches

Here is a program with no annotations and one pair of stray quotes:

TypeScript
const adults = 2;
const children = "3";

console.log("Riders:", adults + children);
Output
Riders: 23

No message, and a wrong answer. The quotes make "3" text, and + between a number and text joins them together instead of adding, so two adults and three children become 23 riders. The compiler let it through, because nothing said children had to be a number, and joining text with + is allowed.

Now the same program with the intention written down:

TypeScript
const adults: number = 2;
const children: number = "3";

console.log("Riders:", adults + children);
Output
main.ts(2,7): error TS2322: Type 'string' is not assignable to type 'number'.

Nothing printed at all, not even a wrong number. Read the message in three pieces:

  • main.ts(2,7) is where: line 2, character 7, which is where the name children begins.
  • TS2322 is the compiler's own number for this kind of problem. You can ignore it for now.
  • Type 'string' is not assignable to type 'number'. is what went wrong. Assignable means allowed to be stored in: the value is a string, and the name was promised a number.

Fix the value, not the promise

Making that message disappear is not the same as fixing the program. Change the annotation to match the quotes, and the text simply causes trouble somewhere else:

TypeScript
const children: string = "3";
const childFare: number = 25;

console.log("Fare:", children * childFare);
Output
main.ts(4,22): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.

That is the message the egg boxes showed for dividing text. A count of children really is a number, so the annotation was right all along, and the quotes were the mistake.

Your turn

Press Run first. No ticket appears. The output panel shows the compiler's message instead:

Output
main.ts(9,7): error TS2322: Type 'string' is not assignable to type 'number'.

Go to line 9, find the value the compiler is pointing at, and fix it so it matches its annotation. Leave every : number and : string exactly as it is. When it works, the ticket shows 5 riders and a fare of 155.

If something goes wrong

If a new message appears about the left-hand side of an arithmetic operation, the quotes are still there and the annotation has been changed or deleted instead. Without : number, the compiler decides from the quotes that children is a string, and the fare sum is refused. Put : number back and take the quotes away.

Number with a capital N is a different thing from number. With it, both sums are refused, and the first message reads Operator '+' cannot be applied to types 'number' and 'Number'. The built-in types, number and string, are always written in small letters.

Whatever the message, nothing on the ticket prints until every line passes the check. That is not a second problem; it is the compiler refusing to run a program it already knows is wrong.

Write your code

Runs in your browser. Press Run (or Ctrl/Cmd+Enter) and the output is checked for you.

Ctrl/Cmd+Enter to run

Press Esc then Tab to move keyboard focus out of the code editor.

Ready
Output will appear here after you run your code.

The runtime is starting in the background. You can type now — it will be ready before you are.

The answer appears here once you have run your code at least once.

Things that often go wrong here

Changing : number to : string to make the message go away
The first message disappears and a new one arrives on the fare line: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. A count of children is a number, so the annotation was telling the truth and the quotes were not.
Deleting the annotation and keeping the quotes
Without : number the compiler decides from the quotes that children is a string, and it refuses the fare sum with that same arithmetic message. The problem has not gone away; it is only being reported further down.
Writing Number with a capital N
Number with a capital is not the same type as number, so both sums are refused: the riders line with Operator '+' cannot be applied to types 'number' and 'Number'. and the fare line with the arithmetic message. The built-in types number and string are always written in small letters.
Expecting the rest of the ticket to print
A type error stops the whole program, not just its own line. Nothing prints until every line passes the check, which is why the output panel shows only the compiler's message.

Want a blank editor instead? Open the TypeScript playground.