Exercise 10 of 10 · A complete program
The Bike Shop Receipt
What you will make
A printed bike repair receipt: the shop name, three charges in straight columns, a subtotal, a workshop charge the program works out itself, a total, and the notes at the bottom.
The one new idea: assembling a complete program out of parts you already know
Real software is rarely one clever idea. It is ordinary parts arranged in the order the work happens, and being able to name each part of a finished program is what lets you read other people's TypeScript. The types running through it are what let the compiler check that all those parts still fit together.
Go straight to the code ↓Everything you know, in one program
Nothing in this exercise is new. Every line in the editor is something an earlier exercise taught, and here they all work on one receipt:
console.logprints each line. Exercise 1.constnames every value, and none of them changes once named. Exercise 2.*andMath.floorwork out the amounts and the workshop charge. Exercise 3.: numberand: stringstate what each name holds. Exercise 4.ifandelsedecide whether a workshop charge applies. Exercise 5.cost,lineandworkshopChargeare functions with typed parameters. Exercise 6.- Template literals with
padEndandpadStartline the columns up. Exercise 7. - The notes are a
string[]walked byfor...of. Exercise 8. Chargeis an object type that every charge is checked against. Exercise 9.
Reading it the way the compiler does
Start at the top. type Charge describes one line of a repair bill: a label, a quantity and a price. The three
functions after it each do one job, and each says in its first line what it takes and what it hands back.
workshopCharge is the only one with a decision in it. Each branch of its if ends in its own return, so
whichever block runs is the one that hands the answer back, and the : number on its first line holds both
branches to the same promise:
function discount(total: number): number {
if (total >= 100) {
return 10;
} else {
return "none";
}
}
console.log(discount(120));main.ts(5,5): error TS2322: Type 'string' is not assignable to type 'number'.Below the functions come the three charges, each checked against Charge, and then three names that depend on
each other: the subtotal needs the charges, the workshop charge needs the subtotal, and the total needs both.
The compiler knows that order matters. Use a name on a line above the one that creates it, and nothing runs:
const price: number = 40;
const total: number = price + tip;
const tip: number = 4;
console.log(total);main.ts(2,31): error TS2448: Block-scoped variable 'tip' used before its declaration.
main.ts(2,31): error TS2454: Variable 'tip' is used before being assigned.Two messages about the same spot, both saying that tip is used on line 2 but only created on line 3.
A worked example
A tea stall rather than a bike shop, so the receipt in the editor stays yours to finish:
type Item = {
name: string;
price: number;
};
function row(item: Item): string {
return `${item.name.padEnd(10)}${String(item.price).padStart(5)}`;
}
const tea: Item = { name: "Green tea", price: 60 };
const bun: Item = { name: "Bun", price: 35 };
const total: number = tea.price + bun.price;
console.log(row(tea));
console.log(row(bun));
console.log("---------------");
console.log(`TOTAL${String(total).padStart(10)}`);Green tea 60
Bun 35
---------------
TOTAL 95Only the names and prices are typed in. Change the bun to 40, and its row and the total both follow without anyone retyping either.
Your turn
Press Run before changing anything. Most of the receipt is right: the header, all three charge rows and the notes. Two lines are marked, and both already run, so they are wrong rather than missing.
- The subtotal adds up the tube and the brake pads but leaves out the labour, so it reads 610. Add the third charge the same way the first two are added.
- The total is
0. Work it out from the two names that already hold its parts: the subtotal and the workshop charge.
When both are right, the total reads 955. Then change the labour from two hours to three and run it again: the labour row, the subtotal, the workshop charge and the total all move together.
If something goes wrong
If the compiler reports Operator '+' cannot be applied to types 'number' and 'Charge'., the subtotal adds
labour itself instead of what it costs. labour is a whole Charge object; cost(labour) is a number.
If the subtotal reads 760 with no message, it adds labour.price, the price of a single hour, instead of the
cost of both hours. The compiler cannot catch that one, because both are numbers.
If the compiler reports Block-scoped variable 'service' used before its declaration., the total line has moved
above the line that creates service. Put it back underneath.
And if the total is right because 955 was typed in, it is right only until something on the receipt changes.
Write your code
Runs in your browser. Press Run (or Ctrl/Cmd+Enter) and the output is checked for you.
Press Esc then Tab to move keyboard focus out of the code editor.
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
- Adding labour itself instead of cost(labour)
- labour is a whole Charge object with a label, a quantity and a price, and a number cannot have an object added to it. The compiler stops before anything prints with Operator '+' cannot be applied to types 'number' and 'Charge'.
- Adding labour.price instead of cost(labour)
- The receipt prints with a subtotal of 760: the price of one hour instead of the cost of both. The compiler cannot see this one, because a price and a cost are both numbers. cost is the function that multiplies by the quantity.
- Moving the total above the workshop charge
- The total needs service, and service does not exist until its own line. The compiler notices the order before running and reports Block-scoped variable 'service' used before its declaration.
- Leaving the workshop charge out of the total
- The total reads 910, which is the subtotal again, while the workshop line above it shows a charge of 45. A total is everything the customer pays, so both names belong on the right of the equals sign.
- Typing the total in by hand
- 955 is right this minute and wrong the moment anything changes. Make it three hours of labour and the row, the subtotal and the workshop charge all update, while a typed total sits underneath contradicting them.
Want a blank editor instead? Open the TypeScript playground.