Aufwärmen · Aufgabe 1 von 7
// B2.3 · ca. 28 Min. · Einstieg
Objekttypen und optionale Eigenschaften
Nach dieser Lektion beschreiben Sie Objekte mit Objekttypen, prüfen optionale Eigenschaften vor der Nutzung auf undefined und beheben Tippfehler, die tsc in Objektliteralen findet.
Danach können Sie
- Eine Variable oder einen Parameter mit einem Objekttyp annotieren und die Fehler zu fehlenden, überzähligen oder falsch typisierten Eigenschaften lesen
- Eine Eigenschaft mit ? optional machen und sie vor der Nutzung auf undefined prüfen
- Erklären, wann die Prüfung auf überzählige Eigenschaften greift, und den gemeldeten Tippfehler beheben
Vorhersagen · Aufgabe 2 von 7
Sagen Sie es vorher, bevor Sie weiterlesen: Welche Zeile meldet tsc?
const book: { title: string; year: number } = { title: "Dune", year: 1965 }; console.log(book.title.toUpperCase()); console.log(book.author);Üben · Aufgabe 3 von 7
Füllen Sie die Lücke so, dass last weggelassen werden darf: tsc soll beide Aufrufe akzeptieren, und das Programm gibt Bob aus, dann Alice Alisson.
function printName(obj: { first: string; last ____: string }) { return obj.last === undefined ? obj.first : obj.first + " " + obj.last; } console.log(printName({ first: "Bob" })); console.log(printName({ first: "Alice", last: "Alisson" }));function printName(obj: { first: string; last : string }) {Üben · Aufgabe 4 von 7
last ist optional. Was meldet tsc?
function printName(obj: { first: string; last?: string }) { console.log(obj.first + " " + obj.last.toUpperCase()); }Üben · Aufgabe 5 von 7
box hat eine Eigenschaft, die der Parametertyp nicht nennt. Was meldet tsc?
function area(box: { width: number; height: number }) { return box.width * box.height; } const box = { width: 2, height: 3, colour: "red" }; console.log(area(box));Denksport · Aufgabe 6 von 7
Knobelaufgabe. tsc meldet keine Fehler. Was gibt node main.ts aus?
function count(item: { quantity?: number }) { return item.quantity || 1; } console.log(count({ quantity: 0 }));Anwenden · Aufgabe 7 von 7
Kleine Aufgabe. Schreiben Sie eine Funktion formatAddress, die ein Objekt mit street, city und optionalem postcode nimmt, alles Strings, und ohne Postleitzahl Hauptstr. 1, Bonn liefert, mit Postleitzahl Hauptstr. 1, 53111 Bonn. Annotieren Sie den Parameter mit einem Objekttyp und prüfen Sie postcode auf undefined. Rufen Sie sie auf beide Arten auf. Schreiben Sie dann in einem Aufruf eine Eigenschaft falsch, etwa sity, und lesen Sie, was tsc sagt.
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
Bestellzeilen mit optionalen Eigenschaften
formatLine nimmt ein Objekt. name und price sind Pflicht; quantity und note sind optional, Aufrufer lassen sie also weg, wenn sie nichts dazu zu sagen haben. Die Funktion gibt quantity mit ?? einen Standardwert und prüft note auf undefined, bevor sie toUpperCase aufruft. Die letzten beiden Zeilen annotieren eine Variable mit einem Objekttyp. Führen Sie npx tsc aus, dann node main.ts. Löschen Sie danach das if um die note-Zeile und starten Sie tsc erneut, oder geben Sie einem der Aufrufe eine Eigenschaft, die der Typ nicht kennt.
main.ts
// A shop's order lines. quantity and note are optional: callers may leave them out.
function formatLine(item: { name: string; price: number; quantity?: number; note?: string }): string {
const quantity = item.quantity ?? 1;
let line = item.name + " x" + quantity + " = " + (item.price * quantity).toFixed(2);
if (item.note !== undefined) {
line += " (" + item.note.toUpperCase() + ")";
}
return line;
}
console.log(formatLine({ name: "Coffee", price: 3.2 }));
console.log(formatLine({ name: "Bagel", price: 2.5, quantity: 2 }));
console.log(formatLine({ name: "Tea", price: 2.8, quantity: 3, note: "no sugar" }));
const order: { id: number; customer: string } = { id: 17, customer: "Ada" };
console.log("Order", order.id, "for", order.customer);
Ausführen mit
npx tsc
node main.tsAusgabe
Coffee x1 = 3.20
Bagel x2 = 5.00
Tea x3 = 8.40 (NO SUGAR)
Order 17 for Ada- Der erste Aufruf übergibt weder quantity noch note, und tsc akzeptiert ihn: Beide sind optional.
- item.quantity ?? 1 ergibt nur dann 1, wenn quantity undefined ist; eine Menge von 0 bliebe 0.
- Innerhalb des if weiß TypeScript, dass note ein String ist, also ist toUpperCase erlaubt.
- order ist mit einem Objekttyp annotiert; order.total zu lesen, wäre error TS2339.
Ä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
Dem Parameter einen Objekttyp geben
tsc lehnt diese Funktion ab: Parameter 'book' implicitly has an 'any' type. Annotieren Sie book mit einem Objekttyp, der die drei Eigenschaften nennt, die die Funktion liest: title und author sind Strings, year ist eine Zahl. Ergänzen Sie auch den Rückgabetyp string. Starten Sie die Tests: Der erste ist die Typprüfung.
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
Ein Objekttyp steht nach dem Parameternamen, wie jede Annotation: book: { … }.
Hinweis 2
In den geschweiften Klammern steht jede Eigenschaft mit ihrem Typ, getrennt durch ;: title: string; author: string; year: number.
Hinweis 3
Die fertige erste Zeile lautet export function describeBook(book: { title: string; author: string; year: number }): string {
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export function describeBook(book: { title: string; author: string; year: number }): string {
return book.title + " by " + book.author + " (" + book.year + ")";
}
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 describeBook(book) {
return book.title + " by " + book.author + " (" + book.year + ")";
}
main.test.ts
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {describeBook} from './main.ts';
test('describeBook liefert Titel, Autor und Jahr', () => {
assert.equal(describeBook({title: 'Dune', author: 'Frank Herbert', year: 1965}), 'Dune by Frank Herbert (1965)', 'describeBook sollte Dune by Frank Herbert (1965) liefern');
});
test('describeBook funktioniert auch für ein anderes Buch', () => {
assert.equal(describeBook({title: 'Emma', author: 'Jane Austen', year: 1815}), 'Emma by Jane Austen (1815)', 'describeBook sollte Emma by Jane Austen (1815) liefern');
});
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 optionalen Rabatt prüfen
priceLabel soll ohne Rabatt nur den Namen liefern, sonst den Namen mit dem Rabatt: Mug (-15%). Ein Rabatt von 0 wurde bewusst angegeben und wird trotzdem gezeigt: Pen (-0%). tsc meldet 'product.discount' is possibly 'undefined', und ein Produkt ohne Rabatt lässt das Programm abstürzen. Prüfen Sie discount auf undefined, bevor Sie es verwenden.
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
discount hat den Typ number | undefined. Behandeln Sie zuerst den Fall undefined und kehren Sie früh zurück.
Hinweis 2
if (!product.discount) erfasst auch 0, das der dritte Test absichtlich übergibt. Vergleichen Sie stattdessen mit undefined.
Hinweis 3
Fügen Sie if (product.discount === undefined) return product.name; vor dem vorhandenen return ein.
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export function priceLabel(product: { name: string; discount?: number }): string {
if (product.discount === undefined) return product.name;
return product.name + " (-" + product.discount.toFixed(0) + "%)";
}
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 priceLabel(product: { name: string; discount?: number }): string {
return product.name + " (-" + product.discount.toFixed(0) + "%)";
}
main.test.ts
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {priceLabel} from './main.ts';
test('ein Produkt ohne Rabatt zeigt nur seinen Namen', () => {
assert.equal(priceLabel({name: 'Book'}), 'Book', 'priceLabel({name: "Book"}) sollte Book sein');
});
test('ein Rabatt von 15 wird gezeigt', () => {
assert.equal(priceLabel({name: 'Mug', discount: 15}), 'Mug (-15%)', 'priceLabel sollte Mug (-15%) liefern');
});
test('auch ein Rabatt von 0 wird gezeigt', () => {
assert.equal(priceLabel({name: 'Pen', discount: 0}), 'Pen (-0%)', 'ein Rabatt von 0 wurde übergeben, also sollte Pen (-0%) herauskommen');
});
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 Pflichteigenschaft fehlt
const user: { name: string; email: string } = { name: "Ada" };
console.log(user.name);
Was tsc oder Node.js ausgibt
main.ts(1,7): error TS2741: Property 'email' is missing in type '{ name: string; }' but required in type '{ name: string; email: string; }'.Warum, und die Lösung
Jede Eigenschaft eines Objekttyps ist Pflicht, außer sie hat ein ?. Das Literal gibt nur name an, also nennt tsc die fehlende: email. Geben Sie sie an, { name: "Ada", email: "ada@example.com" }, oder, wenn ein Nutzer wirklich keine E-Mail haben darf, machen Sie sie mit email?: string optional und prüfen Sie sie vor der Nutzung.
Eine optionale Eigenschaft ohne Prüfung verwenden
function shout(user: { name: string; nickname?: string }) {
return user.nickname.toUpperCase() + "!";
}
console.log(shout({ name: "Ada" }));
Was tsc oder Node.js ausgibt
main.ts(2,10): error TS18048: 'user.nickname' is possibly 'undefined'.Warum, und die Lösung
nickname kann fehlen, und genau dieser Aufruf lässt es weg: Ohne tsc stoppt node main.ts mit TypeError: Cannot read properties of undefined (reading 'toUpperCase'). Legen Sie fest, was ohne Spitznamen passiert: if (user.nickname === undefined) return user.name + "!"; oder nehmen Sie einen Standardwert, (user.nickname ?? user.name).toUpperCase().
Eine falsch geschriebene Eigenschaft in einem Objektliteral
function paint(options: { color: string; width: number }) {
return options.color + " line, " + options.width + "px";
}
console.log(paint({ colour: "red", width: 2 }));
Was tsc oder Node.js ausgibt
main.ts(5,21): error TS2561: Object literal may only specify known properties, but 'colour' does not exist in type '{ color: string; width: number; }'. Did you mean to write 'color'?Warum, und die Lösung
Das Literal steht direkt im Aufruf, also prüft tsc jede Eigenschaft darin gegen den Typ. colour kennt er nicht, und tsc schlägt color vor. Schreiben Sie color: "red". Das Objekt erst in einer Variablen zu speichern, würde diese Prüfung abschalten, aber paint läse trotzdem ein undefined color.
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.