Zum Inhalt springen

Aufgabe 03 - TypeScript-Katas

Zu Zen-Modus wechseln
  • Du beschreibst Funktionen und Daten zügig und vollständig mit Annotationen, interface und Union Types.
  • Du übersetzt Compiler-Meldungen in verständliche Sätze und erklärst damit, welchen Fehler TypeScript vor dem Programmlauf abgefangen hat.
  • Du typisierst Daten unbekannter Form (unknown) durch eine Prüfung, statt sie mit any oder as nur zu behaupten.
  • Du drückst Fachregeln einer Aufgabenstellung als Typen aus, sodass der Compiler sie erzwingt.

Im Karate ist eine Kata eine kurze, festgelegte Bewegungsfolge, die so oft wiederholt wird, bis sie ohne Nachdenken sitzt. Genau das ist hier das Ziel, nur mit Typen statt Tritten.

Bevor Asynchronität und Framework dazukommen, muss das Typisieren in die Finger: kurze, unabhängige Übungsstücke (Katas) rund um Funktionen, Interfaces und Union Types (siehe Kapitel JavaScript und TypeScript, Einheiten 1.5 und 1.6). Alle Katas landen in katas.ts, jede mit zwei Testaufrufen (console.assert).

Projektordner anlegen siehe https://qiz.at/projektordner

  • Lies vorher kurz https://qiz.at/assignmentsabgabe durch.
  • Nur vollständige Abgaben (siehe https://qiz.at/rules) können positiv bewertet werden.
  • Abgabe- und Testdetails siehe https://qiz.at/assignmentsabgabe
  • Die Übung liegt als Unterordner uebung-03 in deinem Jahres-Repository SJ26_27_4AHITM_SEW_<Benutzername>_exercises, eingerichtet wie in Aufgabe 01 (package.json mit dev und typecheck, tsconfig.json aus npx tsc --init). Du arbeitest allein.
  • median(values: number[]): der Median der Liste. Sortiere eine Kopie, nicht das Original.
  • initials(firstName, lastName): aus “Alex Muster” wird “A.M.”.
  • interface Appointment (Titel, Beginn als Date, Dauer in Minuten, optionaler Raum) und endOf(appointment): liefert den Endzeitpunkt als Date.
  • describeRoom(appointment): liefert den Raum oder "kein Raum reserviert". Pflicht: ??, kein if.

Tipp: Liefert median bei [10, 9, 100] Unsinn, sortiert das Standard-sort Texte statt Zahlen. Es braucht eine Vergleichsfunktion (a, b) => a - b. Hat sorted[middle] den Typ number | undefined, kommt das von noUncheckedIndexedAccess: Lass die Einstellung aktiv und entscheide, was median bei einer leeren Liste liefert. Minuten addierst du über getTime(), eine Minute sind 60_000 Millisekunden.

Vollständig, wenn:

  • katas.ts unter "strict": true ohne Fehler und ohne any kompiliert.
  • jede der vier Funktionen zwei grüne Testaufrufe hat.
  • median eine Kopie numerisch sortiert und den Leer-Fall entscheidet.
  • describeRoom mit ?? und ohne if auskommt.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • describeInput(input: string | number): bei Strings die Länge, bei Zahlen das Vorzeichen. Probier zuerst aus, was ohne typeof-Fallunterscheidung passiert, und notiere die Meldung als Kommentar.
  • type Grade = 1 | 2 | 3 | 4 | 5 und isPassing(grade: Grade). Notiere als Kommentar, was der Compiler bei isPassing(6) meldet, im Original und in eigenen Worten.
  • Leg type-errors.ts in deinen Projektordner und prüfe mit npm run typecheck. Die Datei enthält fünf Fehler. Schreib für jeden als Kommentar in die Datei: Meldung im Original, Übersetzung in einen verständlichen Satz, Behebung. Behebe danach jeden Fehler.

Tipp: Die Übersetzung ist der wichtigste Teil: Sie sagt, was nicht passt und warum, statt die Meldung Wort für Wort ins Deutsche zu übertragen. Prüf mit npm run typecheck, nicht mit npx tsc --noEmit type-errors.ts: Liegt eine tsconfig.json im Ordner, bricht tsc mit einem Dateinamen auf der Kommandozeile ab.

Vollständig, wenn:

  • describeInput mit typeof eingrenzt und die Meldung ohne Fallunterscheidung notiert ist.
  • die Meldung zu isPassing(6) im Original und in eigenen Worten dokumentiert ist.
  • alle fünf Fehler aus type-errors.ts mit Originalmeldung, verständlicher Übersetzung und Behebung kommentiert sind und die Datei fehlerfrei kompiliert.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • overlaps(a, b): Überschneiden sich zwei Termine? Untersuche die Grenzfälle: Ende des einen = Beginn des anderen und ein Termin, der den anderen vollständig umschließt. Teste beide und begründe deine Entscheidung zum Fall “Ende = Beginn” als Kommentar.
  • parseAppointment(raw: unknown): Appointment | null: Der Wert kommt aus JSON.parse und ist von unbekannter Form. Prüf ihn, bevor du ihn verwendest, und liefere null, wenn die Form nicht stimmt. Notiere die Compiler-Meldung, die beim direkten Zugriff auf raw.title erscheint.
  • Teste parseAppointment mit einem gültigen Termin und mit mindestens drei fehlerhaften Eingaben (fehlendes Feld, falscher Typ, ungültiges Datum).

Tipp: Zwei Zeiträume überschneiden sich, wenn jeder vor dem Ende des anderen beginnt. raw.title geht nicht: Richtig so. Prüf zuerst typeof raw === "object" && raw !== null, danach jedes Feld einzeln mit typeof. new Date("2027-13-45") wirft keinen Fehler, sondern liefert ein Invalid Date, prüfbar mit Number.isNaN(date.getTime()). Mit exactOptionalPropertyTypes heißt room? “das Feld fehlt”, nicht “das Feld ist undefined”.

Vollständig, wenn:

  • overlaps beide Grenzfälle testet und die Entscheidung zu “Ende = Beginn” begründet ist.
  • parseAppointment Objekt, null, jedes Feld und die Gültigkeit des Datums prüft.
  • die Tests mit gültigen und fehlerhaften Eingaben grün sind und die Meldung zu raw.title notiert ist.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

Modelliere das Sortiment der Schulkantine “Safi”, also Brötchen, Nudeln, Salat, Getränke, Joghurt und dergleichen, so, dass der Compiler die fachlichen Regeln erzwingt:

  • Artikel haben Name und Preis, ihre Ernährungsart ist "vegetarian" | "vegan" | "meat" (etwa Käsebrötchen vegetarisch, Schinkenbrötchen mit Fleisch, Apfelsaft vegan). Ein “Aktionsartikel des Tages” hat zusätzlich einen Wochentag ("monday" | ... | "friday").
  • Schreib vegetarianOnly(items) so, dass der Rückgabetyp Artikel mit Fleisch unmöglich macht.
  • Beweise die Erzwingung: Ein Testaufruf, der dem Ergebnis ein Schinkenbrötchen unterschieben will, muss ein Compile-Fehler sein. Dokumentiere ihn als Kommentar mit der Meldung.
  • Beurteile in drei Sätzen: Welche fachliche Regel steckt jetzt im Typsystem statt in einer Laufzeitprüfung, und was ist der Gewinn?

Tipp: Ein eigener Union Type für die Ernährungsart hilft. Die Schreibweise für eigene Prüffunktionen (item is VegetarianItem) steht im Kapitel im Abschnitt zu any und unknown.

Vollständig, wenn:

  • der Rückgabetyp von vegetarianOnly Fleisch ausschließt.
  • der Schmuggel-Versuch als Compile-Fehler mit Meldung belegt ist.
  • die Beurteilung stichhaltig ist.

Wie unter Allgemein.

  1. Warum sortiert median eine Kopie statt des übergebenen Arrays?
  2. Wie erzwingt string | number eine Fallunterscheidung, und womit trifft man sie?
  3. Was ist der Unterschied zwischen type Grade = 1 | 2 | 3 | 4 | 5 und number mit Laufzeitprüfung?
  4. Wozu ein optionales Feld (room?) statt room: string | null? Nenn einen Unterschied.
  5. Was bedeutet die Rückgabetyp-Schreibweise item is VegetarianItem?
  6. Warum verlangt ein Wert vom Typ unknown eine Prüfung, bevor man ein Feld liest?

Durchschnittlich bis Wesentlich_vollständig: ca. 100 min

  • Oliver Maurhart (MAO)
  • Michael Gabriel (GAM)

CC-BY-SA

https://qiz.at/rules