Zum Inhalt springen

Aufgabe 01 - TypeScript-Spickzettel

Zu Zen-Modus wechseln
  • Du legst ein Node.js-Projekt an, installierst Werkzeuge als devDependencies und definierst und startest Skripte in der package.json.
  • Du erklärst die Aufgabe der Sperrdatei, begründest, warum sie ins Repository gehört und node_modules/ nicht, und stellst die Umgebung mit npm ci wieder her.
  • Du setzt const/let, beide Funktionsschreibweisen, map/filter/reduce, Objektliterale, Template-Literale und Module sicher ein.
  • Du untersuchst, warum eine Kopie mit Spread flach ist und wann ?? etwas anderes liefert als ||.
  • Du beschreibst Daten mit interface und erklärst, welche Fehler TypeScript vor dem Programmlauf abfängt.

Jede Profi-Köchin hat ihr eigenes Rezeptbuch mit Notizen am Rand, nicht, weil sie die Rezepte nicht kennt, sondern weil sie beim Kochen nicht suchen will. Genau so ein Nachschlagewerk baust du dir hier für das ganze Jahr.

Du richtest die Werkzeugkette des Jahres ein (Node.js, npm, TypeScript) und erstellst deinen persönlichen Spickzettel der Sprachkonstrukte (siehe Kapitel JavaScript und TypeScript, Einheiten 1.1 bis 1.5, und Kapitel npm: Pakete und Projekte). Der Lerneffekt liegt im Weg dorthin: Jedes Konstrukt wird einmal selbst getippt, ausgeführt und in eigenen Worten beschrieben.

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-01 in deinem Jahres-Repository SJ26_27_4AHITM_SEW_<Benutzername>_exercises (siehe Einheit 1.1 Werkzeuge einrichten, Abschnitt “Wo deine Projekte liegen”). Du arbeitest allein.
  • Prüfe node --version und npm --version. Leg den Projektordner uebung-01 an und führe darin npm init -y aus. Stell in der package.json den Eintrag "type" auf "module", dann npm install --save-dev typescript tsx und npx tsc --init.
  • Schreib hello.ts mit einer Ausgabe über ein Template-Literal. Ergänze unter scripts die Einträge "dev": "tsx hello.ts" und "typecheck": "tsc --noEmit" und starte beide mit npm run dev und npm run typecheck.
  • Bau absichtlich einen Typfehler in hello.ts ein (etwa const count: number = "drei";) und führe beide Skripte erneut aus. Notiere in einer Datei answers.md, welches Skript den Fehler meldet und welches nicht, und lass die Zeile danach als Kommentar stehen.
  • Leg eine .gitignore mit node_modules/ an. Beantworte in answers.md in je einem Satz: Warum sind typescript und tsx unter devDependencies gelandet? Was bedeutet das Zeichen ^ vor der Versionsnummer? Warum gehört node_modules/ nicht ins Repository, die package-lock.json dagegen schon?
  • Lösch node_modules/ und stell den Zustand mit npm ci wieder her. Notiere in answers.md, woher npm ci weiß, welche Versionen es installieren soll.

Tipp: npx tsc --init erzeugt eine tsconfig.json voller Kommentare. Das ist normal. Lass die Voreinstellungen stehen, wichtig ist vor allem, dass "strict": true aktiv bleibt. Die Antworten zu ^, Sperrdatei und npm ci findest du im Kapitel npm: Pakete und Projekte, Abschnitt “Versionen: das Kernkonzept”.

Vollständig, wenn:

  • npm ci, npm run dev und npm run typecheck im Projektordner fehlerfrei laufen.
  • node_modules/ nicht im Repository liegt, package.json und package-lock.json schon.
  • answers.md alle fünf Fragen fachlich richtig und in eigenen Worten beantwortet.
  • der absichtliche Typfehler als Kommentar in hello.ts steht und in answers.md erklärt ist, warum nur typecheck ihn meldet.

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):

  • Lade die Vorlage cheatsheet.md in deinen Projektordner. Trag für jedes der fünf Konstrukte ein selbst getestetes Mini-Beispiel und einen Satz ein, wann du das Konstrukt verwendest: const und let, Funktionsdeklaration und Arrow Function, map/filter/reduce an einer Zahlenliste, Objektliteral (anlegen, Punktzugriff, Feld ergänzen) und Template-Literal mit eingebettetem Ausdruck.
  • Jedes Beispiel läuft vor dem Eintragen in der Node-REPL oder per npx tsx. Ungeprüfte Beispiele haben auf dem Zettel nichts verloren.
  • Verteil Code auf zwei Dateien: Ein Modul exportiert mindestens eine Konstante und eine Funktion, eine zweite Datei main.ts importiert und verwendet sie. Stell das Skript dev auf tsx main.ts um. npm run dev und npm run typecheck laufen danach beide fehlerfrei.

Tipp: Meldet npm run typecheck beim import den Fehler TS1295 oder TS1287, steht in der package.json noch "type": "commonjs". Bei TS2835: Relative import paths need explicit file extensions fehlt die Endung: Im import steht .js, auch wenn die Datei .ts heißt (from "./clip-format.js"). Ein Beispiel für ein Modul findest du in Einheit 1.4 Moderne Sprachmittel, Abschnitt “Module”.

Vollständig, wenn:

  • cheatsheet.md alle fünf Konstrukte mit je einem lauffähigen Beispiel und einem Satz zur Verwendung enthält.
  • der Import über zwei Dateien funktioniert und npm run dev sowie npm run typecheck fehlerfrei laufen.

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):

  • Schreib eine Datei copies.ts, die ein Objekt mit Spread kopiert, dabei ein Feld überschreibt und zwei Objekte zusammenführt ({ ...object, field: value }).
  • Untersuche die Kopie: Ändere in der Kopie einmal ein einfaches Feld und einmal ein verschachteltes Array und vergleiche beide Male mit dem Original. Erkläre in einem Kommentar, warum sich das Original im zweiten Fall mit ändert, und zeig eine Kopie, bei der das nicht passiert.
  • Zeig in derselben Datei einen Fall, in dem || das Falsche täte und ?? das Richtige (0 als gültiger Wert).
  • Schreib in clip.ts ein interface Clip (Dateiname, Dauer in Sekunden, optionale fps) und eine Funktion, die nur dieses Interface akzeptiert. Bau einen Tippfehler im Feldnamen ein und notiere als Kommentar die Compiler-Meldung im Original und in eigenen Worten.

Tipp: Wenn die flache Kopie “nicht funktioniert”, ist genau das die Beobachtung. Für den ??-Fall eignen sich Werte, bei denen 0 sinnvoll ist: Lautstärke, Anzahl, Rabatt. Einheit 1.4 zeigt die flache Kopie im Abschnitt “Spread und Rest”.

Vollständig, wenn:

  • copies.ts beide Änderungen an der Kopie zeigt, die Erklärung zum geteilten Array stimmt und eine tiefere Kopie das Original unverändert lässt.
  • der ||-gegen-??-Fall mit einem gültigen 0 am laufenden Code sichtbar ist (Ausgabe oder console.assert).
  • die Compiler-Meldung zum Tippfehler im Original und in einem eigenen Satz dokumentiert 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):

  • Zeig in analysis.ts Destructuring von Objekt und Array, auch in einer Parameterliste, dazu je einmal Umbenennen ({ filename: name }), Standardwert ({ fps = 25 }) und Rest (...values) als Parameter.
  • Zeig ?. an einem verschachtelten Feld, das fehlen darf, kombiniert mit ?? für einen Ersatzwert.
  • Erweitere das Interface Clip um tags: string[] und schreib longestPerTag(clips: Clip[]): Map<string, Clip>: je Tag der längste Clip.
  • Definiere type ClipState = "raw" | "editing" | "approved", erweitere Clip darum und schreib countByState(clips: Clip[]): Record<ClipState, number>. Lass testweise einen Zustand im Ergebnisobjekt weg und notiere die Meldung des Compilers.
  • Löse eine der beiden Funktionen einmal mit Schleife und einmal mit map/filter/reduce und vergleiche beide Fassungen in zwei Sätzen.
  • Beurteile in drei Sätzen, welche Prüfungen aus den beiden Funktionen TypeScript zur Compile-Zeit übernimmt und was ohne Typen erst zur Laufzeit (oder nie) aufgefallen wäre.

Tipp: Startet reduce mit einem leeren Objekt und as Record<...>, ist die Vollständigkeitsprüfung wieder ausgehebelt. Ein Typargument (clips.reduce<Record<ClipState, number>>(...)) prüft das Startobjekt.

Vollständig, wenn:

  • Destructuring, Umbenennen, Standardwert, Rest und ?. mit ?? lauffähig gezeigt sind.
  • longestPerTag und countByState typisiert sind und mit je zwei console.assert getestet werden.
  • die Compiler-Meldung zum fehlenden Zustand dokumentiert ist.
  • Vergleich und Beurteilung fachlich stichhaltig sind.

Wie unter Allgemein.

  1. Warum ändert sich nach const copy = { ...original } und copy.tags.push("x") auch original.tags?
  2. Wann liefert value ?? "x" etwas anderes als value || "x"?
  3. Was gehört von node_modules/, package.json und package-lock.json ins Repository, und warum?
  4. Was unterscheidet npm install von npm ci, und wofür ist welcher Befehl gedacht?
  5. Was prüft TypeScript beim Kompilieren, was bleibt Laufzeitverhalten?
  6. Was bedeutet der Fehler Property 'durationSeconds' is missing in type ...?
  7. Warum reicht es nicht, dass npm run dev fehlerfrei läuft, um zu wissen, dass die Typen stimmen?

Durchschnittlich bis Wesentlich_vollständig: ca. 100 min

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

CC-BY-SA

https://qiz.at/rules