Exercise 7 of 10 · Strings and formatting
The League Table
What you will make
A league table whose team names, games played and points all sit in straight columns, every row built by the one function you rewrote.
The one new idea: template literals build text with values inside it
Tables, receipts, timetables and log files are all text with values placed at fixed positions. Template literals are how TypeScript builds that text, and because every row here comes from one function, a single fix in one place tidies every row that uses it.
Go straight to the code ↓Text with values inside it
So far, text and values have shared a line by sitting side by side in console.log, separated by commas, with
exactly one space between them. That is fine until you want a column, which needs every value to take up a fixed
amount of room.
A template literal is a single piece of text with values dropped into it. It is written between backtick
quotes (on US and UK keyboards, the key to the left of the 1), and anywhere inside it, ${...} marks a place for a
value:
const city: string = "Lisbon";
const degrees: number = 24;
console.log(`${city} is ${degrees} degrees today`);
console.log("${city} is ${degrees} degrees today");Lisbon is 24 degrees today
${city} is ${degrees} degrees todayThe two lines differ only in their quotes. In double quotes, the dollar signs and braces are ordinary characters.
Anything that works out to a value can go inside the braces, so ${degrees + 3} would put 27 there.
padEnd and padStart make columns
A column is a fixed width, and two things text can do make one:
.padEnd(9)adds spaces to the end of a piece of text until it is 9 characters long..padStart(4)adds spaces to the start instead, so numbers of different lengths end in the same place.
Those belong to text, not to numbers, and the compiler knows the type of every value. Ask a number to pad itself and nothing runs:
const degrees: number = 24;
console.log(degrees.padStart(4));main.ts(3,21): error TS2339: Property 'padStart' does not exist on type 'number'.A property is something a value has or can do. String(degrees) turns the number into text first, and text
can be padded:
const city: string = "Lisbon";
const degrees: number = 24;
console.log(`[${city.padEnd(9)}][${String(degrees).padStart(4)}]`);
console.log(`[${"Oslo".padEnd(9)}][${String(7).padStart(4)}]`);[Lisbon ][ 24]
[Oslo ][ 7]The square brackets are only there to make the spaces visible. Both names take nine characters and both numbers take four, so every bracket lands in the same column.
The function keeps its promise
A function with : string after its brackets promises to hand text back. Build the template literal but forget
to return it, and that promise is broken:
function label(city: string): string {
`[${city}]`;
}
console.log(label("Oslo"));main.ts(1,31): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.The long message comes down to this: the function said it would return a string, and it returns nothing at all.
Your turn
Press Run first. The heading and the borders are tidy, but the three rows are ragged, because row still
glues its values together with +. Here is that line on its own, with one call:
function row(team: string, played: number, points: number): string {
return team + " " + played + " " + points;
}
console.log(row("Otters", 8, 14));Otters 8 14Rewrite that return line in the editor as a template literal. The heading is laid out for these widths: the
team name padded to 12 characters, games played to 3, and points to 6, with nothing typed between the three
insertions. Every row changes at once, because every row is built by that one function.
If something goes wrong
If every row prints dollar signs and braces back at you, the line is still in double quotes. Nothing has broken; the quotes need to be backticks.
If the compiler reports Property 'padStart' does not exist on type 'number'., a number is being padded before it
has been turned into text. Wrap it in String(...) first.
If the rows print but sit in the wrong place, compare your three widths with 12, 3 and 6, and check that
padEnd is on the team name and padStart on the two numbers.
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
- Leaving the line in double quotes
- Every row prints the dollar signs, the braces and the names back at you, character for character. The compiler has no complaint, because text with braces in it is perfectly good text; only backtick quotes turn those braces into places for values.
- Padding a number without String around it
- Padding is something text can do and a number cannot, and the compiler knows played is a number, so it stops before anything prints with Property 'padStart' does not exist on type 'number'. Wrapping the number in String first turns it into text.
- Swapping padEnd and padStart
- The team names are pushed to the right of their twelve characters and the numbers to the left of theirs, so each name runs straight into its games-played number and nothing lines up under the heading.
- Deleting return while rewriting the line
- The function promised with : string that it would hand back text. Without return it hands back nothing, and the compiler says so before running: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
Want a blank editor instead? Open the TypeScript playground.