Zum Inhalt springen
aviral gupta

// 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.

Lektion 3 von 5 in B2 Alltägliche Typen

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
  1. Aufwärmen · Aufgabe 1 von 7

    Aufwärmen mit JavaScript-Objekten: Was gilt in einfachem JavaScript? Wählen Sie alle zutreffenden.

    Wählen Sie alle zutreffenden aus.

  2. 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);
  3. Ü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 }) {
  4. Ü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());
    }
  5. Ü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));
  6. 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 }));
  7. 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.ts

Ausgabe

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
  1. Hinweis 1

    Ein Objekttyp steht nach dem Parameternamen, wie jede Annotation: book: { … }.

  2. Hinweis 2

    In den geschweiften Klammern steht jede Eigenschaft mit ihrem Typ, getrennt durch ;: title: string; author: string; year: number.

  3. 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.ts

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

npx tsc
node --test
learnrun.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
  1. Hinweis 1

    discount hat den Typ number | undefined. Behandeln Sie zuerst den Fall undefined und kehren Sie früh zurück.

  2. Hinweis 2

    if (!product.discount) erfasst auch 0, das der dritte Test absichtlich übergibt. Vergleichen Sie stattdessen mit undefined.

  3. 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.ts

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

npx tsc
node --test
learnrun.js herunterladen

Hä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.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Ein Objekttyp listet Eigenschaften und ihre Typen auf

Ein Objekttyp beschreibt einen Wert mit Eigenschaften: { title: string; year: number } sagt, dass der Wert einen title vom Typ string und ein year vom Typ number hat. Er steht überall, wo ein Typ stehen kann, nach einer Variablen oder einem Parameter: function describe(book: { title: string; year: number }). Die Eigenschaften trennen Sie nach Belieben mit ; oder ,. tsc prüft dann beide Seiten. Fehlt einem Objekt eine Eigenschaft, ist das error TS2741 (Property 'year' is missing …), eine Eigenschaft mit falschem Typ ist TS2322, und das Lesen einer Eigenschaft, die der Typ nicht kennt, ist TS2339, wo JavaScript still undefined liefern würde. TypeScript vergleicht nur die Form: Jedes Objekt mit den richtigen Eigenschaften passt.

Optionale Eigenschaften können undefined sein: erst prüfen

Ein ? nach dem Namen macht eine Eigenschaft optional: { first: string; last?: string }. Aufrufer dürfen last weglassen; geben sie es an, muss es ein String sein. In der Funktion kann last also fehlen, und eine fehlende Eigenschaft liefert in JavaScript undefined. Darum behandelt TypeScript p.last als string | undefined, und mit strict ist p.last.toUpperCase() error TS18048: 'p.last' is possibly 'undefined'. Prüfen Sie vor der Nutzung: if (p.last !== undefined) { … }, oder p.last?.toUpperCase(), das undefined liefert, statt zu werfen. Für einen Standardwert passt p.quantity ?? 1; p.quantity || 1 ersetzt auch 0, was selten gewollt ist.

Die Prüfung auf überzählige Eigenschaften findet Tippfehler

Ein Objektliteral, das direkt an einer Stelle mit festgelegtem Typ steht, also bei einer annotierten Variablen oder als Argument, wird zusätzlich geprüft: Jede Eigenschaft darin muss der Typ kennen. paint({ colour: "red", width: 2 }) ist error TS2561, wenn der Typ color sagt, mit Did you mean to write 'color'?; eine überzählige Eigenschaft ohne ähnlichen Namen ist TS2353. Das Handbuch nennt die meisten dieser Fehler Bugs. Die Prüfung gilt nur für frische Literale: Ein Objekt, das schon in einer Variablen steht, darf zusätzliche Eigenschaften haben, solange alles da ist, was der Typ braucht. Beheben Sie den Tippfehler; leiten Sie das Objekt nicht über eine Variable um, nur damit tsc schweigt.

Quellen

Zuletzt geprüft am 30. September 2026