Aufwärmen · Aufgabe 1 von 7
// B1.5 · ca. 45 Min. · Einstieg
Projekt: ein vorhandenes JavaScript-Skript typprüfen
Nach dieser Lektion nehmen Sie ein funktionierendes JavaScript-Skript, benennen es in main.ts um, beheben jede Meldung von tsc unter strengen Einstellungen und zeigen, dass es genau dasselbe ausgibt.
Lektion 5 von 5 in B1 Einrichtung und Grundlagen
Danach können Sie
- Ein Skript umstellen: umbenennen, npx tsc ausführen und die Ausgabe von node main.ts mit der JavaScript-Fassung vergleichen
- Die Parameter und Rückgabetypen annotieren, die tsc meldet, und die Fehler beheben, die diese Annotationen aufdecken
- Werte korrigieren, die JavaScript stillschweigend umgewandelt hat (parseInt, isNaN, Text in Rechnungen), ohne die Ausgabe zu ändern
Vorhersagen · Aufgabe 2 von 7
Sagen Sie es vorher, bevor Sie weiterlesen: Dieses JavaScript gibt 37 aus. In main.ts umbenannt, wie viele Meldungen gibt npx tsc aus?
function percent(part, total) { return part / total * 100; } console.log(parseInt(percent(3, 8)));Üben · Aufgabe 3 von 7
tsc meldete Parameter 'scores' implicitly has an 'any' type. Setzen Sie den Typ ein: Über scores läuft eine Schleife, jedes Element wird zu einer Zahl addiert, und der Aufruf übergibt [92, 88, 95].
function average(scores: ____): number { let sum = 0; for (const score of scores) { sum += score; } return sum / scores.length; } console.log(average([92, 88, 95]).toFixed(1));function average(scores: ): number {Üben · Aufgabe 4 von 7
tsc meldet TS7006 für price und qty in Zeile 1. Sie ändern Zeile 1 in function lineTotal(price: number, qty: number): number { und führen npx tsc erneut aus. Was meldet es jetzt?
function lineTotal(price, qty) { return price * qty; } const prices = [2.5, 1.2, 4]; const qtys = ["2", "5", "1"]; let sum = 0; for (let i = 0; i < prices.length; i++) { sum += lineTotal(prices[i], qtys[i]); } console.log("Sum:", sum.toFixed(2));Üben · Aufgabe 5 von 7
Die JavaScript-Fassung gab 37 aus. Mit welcher neuen Zeile 4 meldet tsc keine Fehler, und das Programm gibt weiter 37 aus?
function percent(part: number, total: number): number { return part / total * 100; } console.log(parseInt(percent(3, 8)));Denksport · Aufgabe 6 von 7
Knobelaufgabe. tsc meldet Parameter 'name' implicitly has an 'any' type. Sie schreiben name: any statt name: string. Wie viele Fehler meldet npx tsc jetzt?
function greet(name) { return "Hi " + name.toUppercase(); } console.log(greet("Ada"));Anwenden · Aufgabe 7 von 7
Kleine Aufgabe. Dieses JavaScript gibt Words: 5, Longest: checking und Over the limit: false aus. Heben Sie diese Ausgabe auf, legen Sie den Code in main.ts ab und führen Sie npx tsc aus. Annotieren Sie beide Parameter und beide Rückgabetypen, führen Sie tsc erneut aus und beheben Sie die Meldung, die dann erscheint. Fertig sind Sie, wenn tsc nichts ausgibt und node main.ts dieselben drei Zeilen ausgibt.
function countWords(text) { return text.split(" ").length; } function longest(words) { let best = ""; for (const word of words) { if (word.length > best.length) best = word; } return best; } const line = "type checking catches mistakes early"; const limit = "5"; console.log("Words:", countWords(line)); console.log("Longest:", longest(line.split(" "))); console.log("Over the limit:", countWords(line) > limit);Prüfen Sie Ihr Ergebnis anhand dieser Liste
Selbst programmieren
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
Ein Wetterprotokoll, umgestellt
Als main.js gab dieses Skript genau die Ausgabe unten aus. In main.ts umbenannt, meldete tsc drei Fehler: main.ts(1,23): error TS7006 für celsius, main.ts(5,18): error TS7006 für values und main.ts(20,40): error TS2345 für parseInt(mean), weil parseInt Text erwartet. Die Korrekturen waren number und number[] an den Parametern, number als beide Rückgabetypen und Math.trunc(mean), das die Nachkommastellen abschneidet wie zuvor parseInt. Die Variablen brauchten keine Annotationen: TypeScript leitet sie ab. Führen Sie npx tsc aus, das nichts ausgibt, dann node main.ts, und vergleichen Sie.
main.ts
function toFahrenheit(celsius: number): number {
return celsius * 9 / 5 + 32;
}
function average(values: number[]): number {
let sum = 0;
for (const value of values) {
sum += value;
}
return sum / values.length;
}
const readings = [18.5, 21, 23.25, 19];
const days = ["Mon", "Tue", "Wed", "Thu"];
for (let i = 0; i < readings.length; i++) {
console.log(days[i], readings[i], "C is", toFahrenheit(readings[i]), "F");
}
const mean = average(readings);
console.log("Average:", mean.toFixed(2), "C");
console.log("Whole degrees:", Math.trunc(mean));
Ausführen mit
npx tsc
node main.tsAusgabe
Mon 18.5 C is 65.3 F
Tue 21 C is 69.8 F
Wed 23.25 C is 73.85 F
Thu 19 C is 66.2 F
Average: 20.44 C
Whole degrees: 20- Die Ausgabe ist dieselbe wie die von main.js: Die Annotationen werden entfernt, bevor Node.js die Datei ausführt.
- readings, days, mean und die Schleifenvariablen haben keine Annotationen; TypeScript hat number[], string[] und number abgeleitet.
- Math.trunc(20.4375) ist 20, wie bei parseInt; die letzte Zeile hat sich also nicht geändert.
- Die Zeilennummern der drei Meldungen sind in main.js und main.ts dieselben: Es kamen nur Typen hinzu.
Ändern und ausführen
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.
Übungen
Übung 1 von 3
Die umgestellten Funktionen annotieren
Das war main.js; die Datei wurde gerade in main.ts umbenannt. Sie funktioniert, aber tsc meldet viermal TS7006. Annotieren Sie jeden Parameter und jeden Rückgabetyp. Ändern Sie sonst nichts: Die Tests rufen die Funktionen auf und prüfen, dass das Programm weiter Berlin: 69.8 F ausgibt.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.
Hinweise
Hinweis 1
celsius wird multipliziert und geteilt, ist also eine Zahl. Über values läuft eine Schleife, die aufsummiert: number[].
Hinweis 2
city wird in Text eingefügt, und auf degrees wird toFixed aufgerufen: string und number.
Hinweis 3
Jeder Rückgabetyp steht hinter der Parameterliste: function label(city: string, degrees: number): string {
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export function toFahrenheit(celsius: number): number {
return celsius * 9 / 5 + 32;
}
export function average(values: number[]): number {
let sum = 0;
for (const value of values) {
sum += value;
}
return sum / values.length;
}
export function label(city: string, degrees: number): string {
return city + ": " + degrees.toFixed(1) + " F";
}
console.log(label("Berlin", toFahrenheit(average([18, 21, 24]))));
Auf dem eigenen Computer ausführen
Installieren Sie TypeScript 7.0 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.ts
export function toFahrenheit(celsius) {
return celsius * 9 / 5 + 32;
}
export function average(values) {
let sum = 0;
for (const value of values) {
sum += value;
}
return sum / values.length;
}
export function label(city, degrees) {
return city + ": " + degrees.toFixed(1) + " F";
}
console.log(label("Berlin", toFahrenheit(average([18, 21, 24]))));
main.test.ts
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
import {toFahrenheit, average, label} from './main.ts';
test('toFahrenheit(100) ist 212', () => {
assert.equal(toFahrenheit(100), 212, 'toFahrenheit(100) sollte 212 sein');
});
test('average([1, 2, 3, 4]) ist 2.5', () => {
assert.equal(average([1, 2, 3, 4]), 2.5, 'average([1, 2, 3, 4]) sollte 2.5 sein');
});
test('label("Oslo", 50) ist Oslo: 50.0 F', () => {
assert.equal(label('Oslo', 50), 'Oslo: 50.0 F', 'label("Oslo", 50) sollte Oslo: 50.0 F sein');
});
test('das Programm gibt weiter Berlin: 69.8 F aus', async () => {
const out = (await runMain()).trimEnd();
assert.equal(out, 'Berlin: 69.8 F', `das Programm gab ${JSON.stringify(out)} aus`);
});
package.json
{
"type": "module"
}
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "nodenext",
"lib": [
"esnext",
"dom"
],
"types": [],
"strict": true,
"noEmit": true,
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true,
"allowImportingTsExtensions": true
},
"include": [
"**/*.ts"
],
"exclude": [
"**/*.test.ts"
]
}
npx tsc braucht TypeScript im Ordner: Führen Sie dort einmal npm install --save-dev typescript aus. tsc prüft die Typen; Node.js führt main.ts aus, indem es sie entfernt.
Programm ausführen:
npx tsc
node main.tsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
npx tsc
node --testlearnrun.js herunterladenÜbung 2 von 3
Korrigieren, was JavaScript stillschweigend umgewandelt hat
Die Parameter sind schon annotiert, und das Programm gibt 4 true false 42 aus, was richtig ist. tsc meldet trotzdem drei Fehler, jeder an einer Stelle, an der JavaScript einen Wert von selbst umgewandelt hat. Korrigieren Sie jeden so, dass er die Typprüfung besteht, die Funktionen ihre Ergebnisse behalten und das Programm genau dasselbe ausgibt. Lassen Sie die Annotationen, wie sie sind.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.
Hinweise
Hinweis 1
parseInt erwartet Text. Math.trunc(x) schneidet die Nachkommastellen einer Zahl ab, wie hier parseInt.
Hinweis 2
isNaN erwartet eine Zahl. Wandeln Sie den Text vorher bewusst um: isNaN(Number(text)).
Hinweis 3
text * 2 multipliziert Text. Number(text) * 2 sagt ausdrücklich, was JavaScript stillschweigend tat.
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export function wholePages(bytes: number, perPage: number): number {
return Math.trunc(bytes / perPage);
}
export function isNumber(text: string): boolean {
return !isNaN(Number(text));
}
export function double(text: string): number {
return Number(text) * 2;
}
console.log(wholePages(5000, 1024), isNumber("12"), isNumber("abc"), double("21"));
Auf dem eigenen Computer ausführen
Installieren Sie TypeScript 7.0 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.ts
export function wholePages(bytes: number, perPage: number): number {
return parseInt(bytes / perPage);
}
export function isNumber(text: string): boolean {
return !isNaN(text);
}
export function double(text: string): number {
return text * 2;
}
console.log(wholePages(5000, 1024), isNumber("12"), isNumber("abc"), double("21"));
main.test.ts
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
import {wholePages, isNumber, double} from './main.ts';
test('wholePages behält nur ganze Seiten', () => {
assert.equal(wholePages(5000, 1024), 4, 'wholePages(5000, 1024) sollte 4 sein');
assert.equal(wholePages(2048, 1024), 2, 'wholePages(2048, 1024) sollte 2 sein');
});
test('isNumber unterscheidet Zahlen von anderem Text', () => {
assert.equal(isNumber('12'), true, 'isNumber("12") sollte true sein');
assert.equal(isNumber('abc'), false, 'isNumber("abc") sollte false sein');
});
test('double("21") ist 42', () => {
assert.equal(double('21'), 42, 'double("21") sollte die Zahl 42 sein');
});
test('das Programm gibt weiter 4 true false 42 aus', async () => {
const out = (await runMain()).trimEnd();
assert.equal(out, '4 true false 42', `das Programm gab ${JSON.stringify(out)} aus`);
});
package.json
{
"type": "module"
}
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "nodenext",
"lib": [
"esnext",
"dom"
],
"types": [],
"strict": true,
"noEmit": true,
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true,
"allowImportingTsExtensions": true
},
"include": [
"**/*.ts"
],
"exclude": [
"**/*.test.ts"
]
}
npx tsc braucht TypeScript im Ordner: Führen Sie dort einmal npm install --save-dev typescript aus. tsc prüft die Typen; Node.js führt main.ts aus, indem es sie entfernt.
Programm ausführen:
npx tsc
node main.tsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
npx tsc
node --testlearnrun.js herunterladenÜbung 3 von 3
Projekt: den Notenbericht typprüfen
Das Modulprojekt. Dieser Notenbericht war main.js; er gibt sieben richtige Zeilen aus. Bringen Sie ihn unter der Kurs-tsconfig durch die Typprüfung, ohne ein einziges Zeichen der Ausgabe zu ändern. Führen Sie npx tsc (oder die Tests) aus, beheben Sie die erste Meldung und prüfen Sie erneut. Erwarten Sie zuerst sieben Meldungen und eine weitere, nachdem Sie grade annotiert haben. Annotieren Sie jeden Parameter und Rückgabetyp und beheben Sie jede Unstimmigkeit dort, wo der Wert herkommt. Die Tests vergleichen die Ausgabe mit der JavaScript-Fassung.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.
Hinweise
Hinweis 1
Beginnen Sie mit den vier Fehlern TS7006: scores ist number[], avg eine Zahl, name ein String. Ergänzen Sie auch die Rückgabetypen: number, string, string.
Hinweis 2
avg >= passMark vergleicht eine Zahl mit "50", und bonus * 1 multipliziert "5". Speichern Sie beide Werte dort, wo sie deklariert werden, als Zahlen.
Hinweis 3
Aus parseInt(classAverage) wird Math.trunc(classAverage). Nach avg: number wird grade("100") gemeldet: Übergeben Sie die Zahl 100.
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
// Grade report: each student's average, then a summary.
function average(scores: number[]): number {
let sum = 0;
for (const score of scores) {
sum += score;
}
return sum / scores.length;
}
function grade(avg: number): string {
if (avg >= 85) return "A";
if (avg >= 70) return "B";
if (avg >= 50) return "C";
return "F";
}
function formatLine(name: string, avg: number): string {
return name.padEnd(6) + avg.toFixed(1) + " " + grade(avg);
}
const names = ["Ada", "Grace", "Linus"];
const scores = [[92, 88, 95], [71, 64, 80], [45, 52, 38]];
const passMark = 50;
const bonus = 5;
let passed = 0;
let classTotal = 0;
for (let i = 0; i < names.length; i++) {
const avg = average(scores[i]);
classTotal += avg;
console.log(formatLine(names[i], avg));
if (avg >= passMark) passed++;
}
const classAverage = classTotal / names.length;
console.log("Passed:", passed, "of", names.length);
console.log("Class average, whole points:", Math.trunc(classAverage));
console.log("With bonus:", classAverage + bonus * 1);
console.log("A perfect 100 is grade", grade(100));
Auf dem eigenen Computer ausführen
Installieren Sie TypeScript 7.0 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.ts
// Grade report: each student's average, then a summary.
function average(scores) {
let sum = 0;
for (const score of scores) {
sum += score;
}
return sum / scores.length;
}
function grade(avg) {
if (avg >= 85) return "A";
if (avg >= 70) return "B";
if (avg >= 50) return "C";
return "F";
}
function formatLine(name, avg) {
return name.padEnd(6) + avg.toFixed(1) + " " + grade(avg);
}
const names = ["Ada", "Grace", "Linus"];
const scores = [[92, 88, 95], [71, 64, 80], [45, 52, 38]];
const passMark = "50";
const bonus = "5";
let passed = 0;
let classTotal = 0;
for (let i = 0; i < names.length; i++) {
const avg = average(scores[i]);
classTotal += avg;
console.log(formatLine(names[i], avg));
if (avg >= passMark) passed++;
}
const classAverage = classTotal / names.length;
console.log("Passed:", passed, "of", names.length);
console.log("Class average, whole points:", parseInt(classAverage));
console.log("With bonus:", classAverage + bonus * 1);
console.log("A perfect 100 is grade", grade("100"));
main.test.ts
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
const lines = async () => (await runMain()).trimEnd().split('\n');
test('die drei Zeilen der Studierenden sind unverändert', async () => {
const out = (await lines()).slice(0, 3).join('\n');
assert.equal(out, 'Ada 91.7 A\nGrace 71.7 B\nLinus 45.0 F', `die Zeilen der Studierenden waren ${JSON.stringify(out)}`);
});
test('die Zusammenfassung ist unverändert', async () => {
const out = (await lines()).slice(3).join('\n');
assert.equal(
out,
'Passed: 2 of 3\nClass average, whole points: 69\nWith bonus: 74.44444444444444\nA perfect 100 is grade A',
`die Zusammenfassung war ${JSON.stringify(out)}`
);
});
test('der Bericht hat weiter genau sieben Zeilen', async () => {
const count = (await lines()).length;
assert.equal(count, 7, `das Programm gab ${count} Zeilen aus`);
});
package.json
{
"type": "module"
}
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "nodenext",
"lib": [
"esnext",
"dom"
],
"types": [],
"strict": true,
"noEmit": true,
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true,
"allowImportingTsExtensions": true
},
"include": [
"**/*.ts"
],
"exclude": [
"**/*.test.ts"
]
}
npx tsc braucht TypeScript im Ordner: Führen Sie dort einmal npm install --save-dev typescript aus. tsc prüft die Typen; Node.js führt main.ts aus, indem es sie entfernt.
Programm ausführen:
npx tsc
node main.tsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
npx tsc
node --testlearnrun.js herunterladenHäufige Fehler
Ein Array-Parameter als einzelne Zahl annotiert
function average(scores: number) {
let sum = 0;
for (const score of scores) {
sum += score;
}
return sum / scores.length;
}
console.log(average(4));
Was tsc oder Node.js ausgibt
main.ts(3,23): error TS2488: Type 'number' must have a '[Symbol.iterator]()' method that returns an iterator.Warum, und die Lösung
number ist eine einzelne Zahl, und über eine einzelne Zahl kann keine for...of-Schleife laufen: Dafür braucht es etwas Iterierbares, etwa ein Array. tsc meldet außerdem, dass number kein length hat. Der Rumpf durchläuft scores, also ist es ein Array von Zahlen: scores: number[]. Ändern Sie dann auch den Aufruf, sodass er ein Array übergibt: average([4]).
Ein Rückgabetyp, der nicht zu dem passt, was die Funktion zurückgibt
function label(avg: number): number {
return avg >= 50 ? "pass" : "fail";
}
console.log(label(70));
Was tsc oder Node.js ausgibt
main.ts(2,22): error TS2322: Type 'string' is not assignable to type 'number'.Warum, und die Lösung
Die Annotation hinter der Parameterliste sagt, was die Funktion zurückgibt, und tsc prüft jedes return dagegen. Hier sind beide Ergebnisse Text, also meldet tsc "pass" in Spalte 22 und "fail" in Spalte 31. Der Code stimmt, die Annotation nicht: Schreiben Sie function label(avg: number): string.
Number mit großem N als Typ
function double(n: Number) {
return n * 2;
}
console.log(double(4));
Was tsc oder Node.js ausgibt
main.ts(2,10): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.Warum, und die Lösung
Der Typ einer Zahl ist number, kleingeschrieben. Laut Handbuch bezeichnen die großgeschriebenen Namen String, Number und Boolean besondere eingebaute Typen, die in Ihrem Code sehr selten vorkommen, und * nimmt kein Number an. Schreiben Sie n: number, und auch string und boolean klein.
TypeScript im Browser: der Compiler von TypeScript 6.0.3, Apache-2.0, danach die eigene Engine Ihres Browsers. Lizenz und Quellcode
Abschlussquiz
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.