Aufwärmen · Aufgabe 1 von 7
// B2.2 · ca. 30 Min. · Einstieg
Annotationen und Typableitung
Nach dieser Lektion annotieren Sie Variablen, Parameter und Rückgabetypen, sagen vorher, was TypeScript ohne sie ableitet, und lassen Annotationen weg, die es nur wiederholen.
Danach können Sie
- Variablen, Parameter und Rückgabetypen annotieren und sagen, wo jede Annotation steht
- Den Typ vorhersagen, den TypeScript aus einem Wert, einem gemischten Array und den return-Anweisungen einer Funktion ableitet
- Kontextuelle Typisierung bei Callbacks erkennen und entscheiden, wann eine Annotation nötig ist
Vorhersagen · Aufgabe 2 von 7
Sagen Sie es vorher, bevor Sie weiterlesen: Welchen Typ leitet TypeScript für mixed ab?
const mixed = [1, "two", 3];Üben · Aufgabe 3 von 7
Ergänzen Sie den Rückgabetyp, damit tsc die Funktion akzeptiert und sie 3.5 ausgibt.
function average(a: number, b: number): ____ { return (a + b) / 2; } console.log(average(3, 4));function average(a: number, b: number): {Üben · Aufgabe 4 von 7
Der Callback hat keine Annotation. Welchen Typ leitet TypeScript für lengths ab?
const names = ["Ada", "Grace"]; const lengths = names.map((name) => name.length);Üben · Aufgabe 5 von 7
Der Rückgabetyp sagt string. Was meldet tsc?
function grade(points: number): string { if (points >= 50) { return "pass"; } }Denksport · Aufgabe 6 von 7
Knobelaufgabe. Beide Zeilen enthalten dieselbe Pfeilfunktion (n) => n * 2, und keines der n hat eine Annotation. Welche Zeilen meldet tsc?
const double = (n) => n * 2; console.log([1, 2, 3].map((n) => n * 2));Anwenden · Aufgabe 7 von 7
Mini-Aufgabe. Beginnen Sie mit const words = ["tree", "sky", "river"]. Behalten Sie mit filter die Wörter mit mehr als 3 Buchstaben, machen Sie sie mit map zu Großbuchstaben und verbinden Sie sie mit einer Funktion joinAll(items: string[]): string. Annotieren Sie nur, was es braucht: den Parameter und den Rückgabetyp von joinAll. Callbacks und Variablen bekommen keine Annotation. Führen Sie npx tsc und node main.ts aus; es gibt TREE, RIVER aus. Schreiben Sie dann toUpperCase im map-Callback falsch und lesen Sie die Meldung: Die kontextuelle Typisierung wusste, dass word ein String ist.
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
Eine Bestellsumme, halb annotiert
Die Kommentare sagen, welche Typen geschrieben sind und welche TypeScript ableitet. Die Parameter der beiden deklarierten Funktionen sind annotiert; prices, label, der Rückgabetyp von sum und price im Callback werden abgeleitet. Führen Sie npx tsc aus, das nichts ausgibt, dann node main.ts. Probieren Sie danach label = 42 oder prices.push("free"): tsc meldet beides, obwohl keine der Variablen eine Annotation hat.
main.ts
// Which types are written, and which does TypeScript infer?
const prices = [4.5, 12, 3.25]; // inferred: number[]
const discount: number = 0.1; // annotated, though 0.1 would give number anyway
let label = "Order"; // inferred: string
function applyDiscount(amount: number, rate: number): number {
return amount * (1 - rate);
}
// No return type written: TypeScript infers number from the return statement.
function sum(values: number[]) {
let total = 0;
for (const value of values) {
total += value;
}
return total;
}
// price needs no annotation: map passes the elements of a number[].
const discounted = prices.map((price) => applyDiscount(price, discount));
label = label + " #42";
console.log(label);
console.log("before:", sum(prices));
console.log("after:", sum(discounted).toFixed(2));
Ausführen mit
npx tsc
node main.tsAusgabe
Order #42
before: 19.75
after: 17.78- prices ist number[] und label ein string, beides aus dem ersten Wert abgeleitet.
- sum hat keinen Rückgabetyp, und doch besteht sum(discounted).toFixed(2) die Prüfung: TypeScript hat number abgeleitet.
- price im map-Callback ist aus seinem Kontext eine Zahl, also wird applyDiscount(price, discount) geprüft.
- Die Annotation bei discount ändert nichts; sie wiederholt nur, was 0.1 ergäbe.
Ä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 2
Nur annotieren, was es braucht
Beide Funktionen funktionieren, aber tsc meldet viermal Parameter … implicitly has an 'any' type. Annotieren Sie die drei Parameter der deklarierten Funktionen: values ist eine Liste von Zahlen, words eine Liste von Texten, minLength eine Zahl. Annotieren Sie word im Callback nicht: Sobald words seinen Typ hat, verschwindet der vierte Fehler von selbst. Rückgabetypen sind hier freiwillig.
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
Eine Liste von Zahlen ist number[], eine Liste von Texten string[].
Hinweis 2
Der Callback (word) => … bekommt seinen Typ von words.filter: Sobald words ein string[] ist, ist word ein String.
Hinweis 3
Die ersten Zeilen werden zu average(values: number[]) und longWords(words: string[], minLength: number).
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export function average(values: number[]): number {
let sum = 0;
for (const value of values) {
sum += value;
}
return sum / values.length;
}
export function longWords(words: string[], minLength: number): string[] {
return words.filter((word) => word.length >= minLength);
}
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 average(values) {
let sum = 0;
for (const value of values) {
sum += value;
}
return sum / values.length;
}
export function longWords(words, minLength) {
return words.filter((word) => word.length >= minLength);
}
main.test.ts
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {average, longWords} from './main.ts';
test('average([2, 4, 9]) ist 5', () => {
assert.equal(average([2, 4, 9]), 5, 'average([2, 4, 9]) sollte 5 sein');
});
test('longWords behält die Wörter mit mindestens 3 Buchstaben', () => {
assert.deepEqual(longWords(['a', 'tree', 'sky'], 3), ['tree', 'sky'], 'longWords(["a", "tree", "sky"], 3) sollte ["tree", "sky"] sein');
});
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 2
Den Fehler vom Rückgabetyp finden lassen
formatScore soll immer Text liefern: ab 50 Prozent "50% (pass)", darunter zum Beispiel "25% (fail)". Ihr Rückgabetyp ist als string annotiert, und tsc meldet die Zeile, die dieses Versprechen bricht. Korrigieren Sie diese Zeile so, dass sie den Prozentwert gefolgt von % (fail) zurückgibt. 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
tsc meldet main.ts(6,3): error TS2322: Type 'number' is not assignable to type 'string'. Zeile 6 gibt die nackte Zahl zurück.
Hinweis 2
Bauen Sie den Text wie in Zeile 4, mit toFixed(0) und einer Endung.
Hinweis 3
Zeile 6 wird zu return percent.toFixed(0) + "% (fail)";
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export function formatScore(points: number, max: number): string {
const percent = (points / max) * 100;
if (percent >= 50) {
return percent.toFixed(0) + "% (pass)";
}
return percent.toFixed(0) + "% (fail)";
}
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 formatScore(points: number, max: number): string {
const percent = (points / max) * 100;
if (percent >= 50) {
return percent.toFixed(0) + "% (pass)";
}
return percent;
}
main.test.ts
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {formatScore} from './main.ts';
test('20 von 40 ist bestanden', () => {
assert.equal(formatScore(20, 40), '50% (pass)', 'formatScore(20, 40) sollte "50% (pass)" sein');
});
test('10 von 40 ist nicht bestanden', () => {
assert.equal(formatScore(10, 40), '25% (fail)', `formatScore(10, 40) sollte "25% (fail)" sein, war aber ${JSON.stringify(formatScore(10, 40))}`);
});
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
Eine Pfeilfunktion ohne Kontext
const double = (n) => n * 2;
console.log(double(21));
Was tsc oder Node.js ausgibt
main.ts(1,17): error TS7006: Parameter 'n' implicitly has an 'any' type.Warum, und die Lösung
Kontextuelle Typisierung wirkt nur dort, wo die Funktion an eine Stelle übergeben wird, die ihre Parameter festlegt, etwa map oder forEach. Eine Funktion in einer Variablen hat keinen solchen Kontext, also kann TypeScript n nicht ableiten, und strict meldet es. Annotieren Sie den Parameter: const double = (n: number) => n * 2. Der Rückgabetyp wird dann als number abgeleitet.
Mit einem Element eines gemischten Arrays rechnen
const scores = [90, "85", 70];
const doubled = scores[1] * 2;
console.log(doubled);
Was tsc oder Node.js ausgibt
main.ts(2,17): 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 beste gemeinsame Typ von 90, "85" und 70 ist (string | number)[], also könnte jedes Element Text sein, und * braucht links eine Zahl. JavaScript gäbe stillschweigend 170 aus. Korrigieren Sie die Daten, nicht die Prüfung: Schreiben Sie 85 ohne Anführungszeichen, dann wird scores zu number[]. Kommt der Text wirklich von außen, wandeln Sie ihn einmal mit Number("85") um.
Ein Rumpf, der seinen Rückgabetyp bricht
function isAdult(age: number): boolean {
return age >= 18 ? "yes" : "no";
}
console.log(isAdult(20));
Was tsc oder Node.js ausgibt
main.ts(2,22): error TS2322: Type 'string' is not assignable to type 'boolean'.Warum, und die Lösung
Die Annotation verspricht einen boolean, und tsc prüft jeden zurückgegebenen Wert dagegen: "yes" (Spalte 22) und "no" (Spalte 30) werden beide gemeldet. Ohne die Annotation würde TypeScript einen String als Rückgabetyp ableiten, und Aufrufer bekämen "yes" statt true. Geben Sie den Vergleich selbst zurück: return age >= 18;
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.