TypeScript-Workshop

Im ersten Teil dieser Serie habe ich mich mit der JavaScript-Alternative TypeScript im Allgemeinen beschäftigt. Im zweiten Teil, dem TypeScript-Workshop, möchte ich Euch einen praktischen Einstieg in die Programmiersprache bieten.

Hierfür erstellen wir zusammen eine HTML5-Webseite und zeigen verschiedene Rechtecke animiert auf einem Canvas-Element an.

Was ist TypeScript?

TypeScript Logo

TypeScript ist eine Programmiersprache von Microsoft, deren Compiler nach JavaScript kompiliert. Diese Sonderform eines Compilers bezeichnet man auch als Transpiler.

Die Sprache bietet Sprachkonstrukte, die in allen modernen Programmiersprachen zu finden sind und die über den Standard der Sprache JavaScript hinausgehen, wie beispielsweise Klassen, Interfaces, Vererbung, Module, anonyme Funktionen, Generics und eine statische Typisierung.

Mehr über die Vorteile der Sprache TypeScript könnt Ihr in meinem vorhergehenden Blog-Artikel „TypeScript als JavaScript-Alternative“ nachlesen.

Vorraussetzungen für den TypeScript-Workshop

Zur Realisierung unserer Demo benötigen wir die Entwicklungsumgebung PHPStorm, alternativ kann auch WebStorm aus der gleichen Entwicklerschmiede verwendet werden. Da der TypeScript-Compiler selbst auch in JavaScript programmiert ist, wird eine Installation von NodeJS benötigt.

Installationsanweisungen für NodeJS gibt es auf der offiziellen Webseite.

In PHPStorm muss anschließend unter Einstellungen > Sprachen und Frameworks > TypeScript sichergestellt werden, dass der Befehl für den Node-Interpreter angegeben ist (Abb. 1). Somit ist alles vorhanden, was PHPStorm zum Umgang mit TypeScript-Projekten benötigt.

1. Einrichten eines neuen Projekts

In unserem Dateisystem erstellen wir einen neuen Ordner beliebigen Ortes und Namens, den wir dann in PHPStorm via Datei > Verzeichnis öffnen als neues Projekt öffnen.

2. Erstellen der HTML-Datei

In unserem Projektverzeichnis erstellen wir nun eine Datei index.html mit dem folgenden minimalem Inhalt:

Wir können diese Datei nun in einem Browser mit guten Developer Tools – beispielsweise Chrome – öffnen und darin alle Fortschritte unserer Entwicklung verfolgen.
Aktuell wird darin lediglich eine leere Seite ohne Titel angezeigt.

3. Erstellen der TypeScript-Konfigurationsdatei

Wir erstellen die Datei tsconfig.json mit dem folgenden Inhalt innerhalb unseres Projektverzeichnisses. Sie enthält alle wichtigen Informationen und Optionen für den TypeScript-Compiler. Zudem impliziert deren Präsenz PHPStorm, dass es sich bei dem Projekt um ein TypeScript-Projekt handelt.

Im Abschnitt include wird angegeben, wo sich die TypeScript-Quelldateien befinden, die vom TypeScript-Compiler kompilieren werden sollen.

Die Compiler-Option outFile legt fest, dass das gesamte Kompilat innerhalb einer einzigen JavaScript-Datei zusammengefasst wird.

Alle in dieser Konfigurationsdatei angegebenen Pfade verstehen sich relativ zur tsconfig.json.

Wird in der tsconfig.json kein explizites Ausgabeformat angegeben, so kompiliert der Compiler standardmäßig in das Zielformat JavaScript ES3 Standard.

— TypeScript-Workshop —

Du möchtest dich oder Dein Team in TypeScript schulen? Christopher Stock bietet dazu den passenden Workshop: Ein praktischer Einstieg mit TypeScript und HTML5. Auf der Workshop-Seite findest Du alle weiteren Informationen.

4. Programmieren der ersten TypeScript-Quelldatei

Da wir unserer tsconfig.json angegeben haben, alle TypeScript-Quellcodes unterhalb des Ordners src/ zu erstellen, legen wir diesen Ordner nun innerhalb unseres Projektverzeichnisses an. Wir wollen im späteren Verlauf unseres Workshops hier auch externe Bibliotheken zum Kompilieren ablegen – daher erzeugen wir nun einen weiteren Unterordner src/custom/, in dem wir all unsere eigenen TypeScript-Quellcodes ablegen werden.

Wir erstellen unsere erste TypeScript-Datei src/custom/Mfg.ts und definieren als deren einzigen Inhalt ein simples JavaScript-Statement:

5. Aktivieren des TypeScript-Compilers

PHPStorm fragt uns bereits beim Ersteller der ersten Quelldatei, ob wir den TypeScript-Compiler für dieses Projekt aktivieren wollen. Falls wir diese Entscheidung zu diesem Zeitpunkt noch nicht bestätigen wollen, kann die Aktivierung des TypeScript-Compilers zu einem späteren Zeitpunkt unter Einstellungen > Sprachen und Frameworks > TypeScript > TypeScript Compiler aktivieren nachgeholt werden (Abb. 2).

Wie in unserer tsconfig.json festgelegt, wurden all unsere TypeScript-Quellcodes nun zu einer einzigen Datei js/custom/Mfg.js kompiliert. Sollte uns PHPStorm diesen neu generierten Ordner nicht unverzüglich in unserem Projektfenster anzeigen, so kann der Fokus im Projektfenster auf unseren Projektordner gesetzt und der Menübefehl Datei > Synchronisieren verwendet werden.

6. Einbinden des Kompilats in unsere Webseite

Damit dieser JavaScript-Quellcode nun auch auf unserer Webseite ausgeführt wird, müssen wir diese Skriptdatei noch in unsere HTML-Seite inkludieren. Dies erfolgt über den Einbau des folgenden Script-Tags in den Kopf unserer HTML-Seite:

Beim erneuten Laden unserer Webseite im Browser wird nun unser erstellter JavaScript-Alert zu sehen sein (Abb. 3).

7. Nutzen der Meldungen des TypeScript-Compilers

Bei jedem Speichern einer TypeScript-Datei kompiliert der TypeScript-Compiler alle TypeScript-Quellcodes selbstständig neu. Der Status sowie mögliche Fehlermeldungen des Compilers werden in dem separaten Fenster TypeScript in PHPStorm angezeigt (Abb. 4). Bei Eingabe eines ungültigen Funktionsaufrufs in unserer Quellcode-Datei wird uns dieses Fenster somit unverzüglich auf diesen Fehler hinweisen.

8. Erstellen von TypeScript-Klassen

Das testweise alert-Statement können wir nun wieder aus der Datei src/custom/Mfg.ts entfernen. Stattdessen wollen wir in dieser Datei nun unsere erste TypeScript-Klasse Mfg definieren. Die Syntax ist hierfür identisch zu denen anderer Hochsprachen:

Mfg soll übrigens als Kürzel für „MayFlowerGame“ fungieren und künftig als Präfix für all unsere eigens erstellten Klassen dienen.

Beim Betrachten des Kompilats wird bereits jetzt deutlich, dass die entsprechende Funktionalität unter Verwendung reiner JavaScript-Syntax wesentlich schwieriger lesbar erscheint:

9. Erstellen statischer Methoden

Als Einstiegspunkt unserer Applikation wollen wir eine statische Methode erstellen, die wir von außerhalb der Klasse aufrufen können. Bei TypeScript können wir für alle Methoden explizit den Rückgabetyp angeben; da die Methode in unserem Fall nichts zurückgibt, setzen wir als Rückgabewert den Typ void ein:

Da diese statische Methode den Einstiegspunkt in unsere Applikation darstellen soll, müssen wir sie von außerhalb der Klasse aufrufen. Hierfür bietet sich an, das JavaScript-Event window.onload zu nutzen, da dieses ausgelöst wird, sobald alle Komponenten unserer Webseite fertig geladen wurden. Daher weisen wir diesem Event eine globale und konventionelle JavaScript-Funktion zu:

10. Aufrufen bestehender JavaScript-Funktionen

In all unseren TypeScript-Codes ist es weiterhin erlaubt, reinen JavaScript-Code zu formulieren, der nach wie vor dynamisch typisiert wird. Als Beispiel definieren wir eine weitere statische Methode innerhalb unserer Klasse Mfg, die den Titel unserer Webseite dynamisch setzt, und rufen sie in unserer statischen main-Methode auf.

Beim Zugriff auf statische Methoden oder Felder muss unter TypeScript immer der Klassenname mit angegeben werden, auch wenn der Zugriff innerhalb der selben Klasse erfolgt. Somit grenzen sich statische Methodenaufrufe auch klar von JavaScript-Funktionsaufrufen ab.

Ein Refresh unserer Webseite im Browser zeigt uns den Effekt dieser Änderung: Ab sofort wird der Titel der Webseite im Browserfenster bzw. im Tab des Browsers angezeigt (Abb. 5).

11. Typisierung von Variablen

Alle Variablen – sowohl lokale Variablen als auch statische und nicht-statische Felder – können unter TypeScript mit einer statischen Typisierung versehen werden. Typisiert werden kann dabei auf eine abstrakte oder konkrete Klasse sowie auf einen der Typen boolean, number, string, void und any. Es existieren zudem noch ein paar spezielle Typen, die für uns hier und heute aber uninteressant sind.

Mit Hilfe der folgenden statischen Methode innerhalb unserer Klasse Mfg können wir das Body-Tag mit Style-Angaben versehen, und dabei die lokale Variable style mit einer eindeutigen Klassenangabe typisieren:

Auch diese statische Methode rufen wir aus unserer main-Methode statisch auf:

Diese Änderung hat nun den Effekt, dass der gesamte Hintergrund unserer Webseite grau wird (Abb. 6). Die restlichen Style-Attribute werden sich erst zu einem späteren Zeitpunkt bemerkbar machen.

12. Erstellen statischer Felder

Als nächstes wollen wir ein statisches Feld in unserer Klasse Mfg erstellen. Wie für alle Variablen lässt sich hierfür der Datentyp genau angeben. Wir wollen in diesem Feld eine Instanz der Klasse MfgDemo erstellen. Diese noch nicht existierende Klasse erstellen wir im nächsten Schritt.

Nach dem Hinzufügen des Feldes sollte das Fehlen dieser Klasse im Ausgabefenster des TypeScript-Compilers durch die Anzeige eines Fehlers deutlich gemacht werden.

13. Instanziieren von Klassen

Die neue Klasse MfgDemo repräsentiert die eigentliche Demo und soll im Gegensatz zur Klasse Mfg in einem reinen nicht-statischen Kontext betrieben werden. Wir legen sie unter src/custom/MfgDemo.ts an und statten sie mit einem Konstruktor und einer nicht-statischen init-Methode aus:

Jetzt können wir in unserer Mfg.main() eine Instanz der Klasse MfgDemo erstellen und sie in unserer statischen Variable demo speichern. Anschließend rufen wir die nicht-statische Methode init unserer neu erstellten Instanz auf:

14. Verwendung nicht-statischer Felder und Methoden

Um unsere Zeichenfläche dynamisch zu erstellen und im Browser anzuzeigen, definieren wir in unserer Klasse MfgDemo jetzt eine neue nicht-statische Methode initCanvas und rufen sie innerhalb unserer nicht-statischen init-Methode auf.

Das Canvas-Tag wird nun dynamisch erstellt, mit einer Größe und Hintergrundfarbe versehen und anschließend an das Body-Tag angehängt.

Für spätere Zugriffe auf das Canvas speichern wir den zugehörigen Rendering Context in einem nicht-statischen Feld ab:

Anschließend bekommen wir im Browser unsere just hinzugefügte und leere Zeichenfläche angezeigt (Abb. 7).

Testweise können wir nach dem Festhalten des CanvasRenderingContext2D eine Zeichenoperation absetzen, damit klar wird, wozu wir für spätere Zugriffe eine Referenz auf diesen Kontext festhalten:

Diese Zeichenoperation wird daraufhin auf unserem Canvas sichtbar (Abb. 8).

Im Anschluss kann diese testweise hinzugefügte Zeichenoperation auch wieder entfernt werden.

15. Definieren der Sichtbarkeit von Feldern und Methoden

Analog zu anderen Hochsprachen können auch unter TypeScript alle Felder und Methoden, egal ob statisch oder nicht-statisch, mit einem der drei Visibility-Modifier public, private oder protected versehen werden. Private Member sind dabei nur aus der selben Klasse aus ansprechbar, Protected Member nur aus der selben sowie aus abgeleiteten und Public Member aus allen Klassen heraus ansprechbar.

16. Nutzen von Arrays und Generics

Arrays bieten uns in TypeScript eine komfortable Möglichkeit, eine Sammlung von Objekten zu verwalten. Da wir im nächsten Schritt verschiedene Rechtecke auf unserer Zeichenfläche anzeigen wollen und sich diese in Position, Größe und Farbe unterscheiden sollen, bietet es sich an, eine eigene Klasse dafür zu definieren. Wir legen die neue Klasse MfgRect unter src/custom/MfgRect.ts an. Diese Klasse enthält alle genannten Attribute sowie eine nicht-statische Methode zum Zeichnen des Rechtecks auf einem Canvas Rendering Context:

In unserer Klasse MfgDemo wollen wir nun verschiedene Rechtecke erstellen und diese in einem typisierten Array ablegen. Hierfür definieren wir die nicht-statische Methode initRects und rufen sie in unserer nicht-statischen init-Methode auf. Das typisierte Array halten wir in dem nicht-statischen Feld rects fest:

Durch den Logbefehl am Ende der nicht-statischen Methode initRects wird die Anzahl der erstellten Rechtecke nun in der Konsole unseres Browsers angezeigt (Abb. 9).

17. Definieren von JavaScript-Callbacks

Statische TypeScript-Methoden sind als JavaScript-Callbacks problemlos nutzbar. Soll allerdings eine nicht-statische Methode als JavaScript-Callback verwendet werden, so muss diese mit einer speziellen Syntax versehen werden („Arrow Function“), damit der Kontext von this beim Aufruf dieser nicht-statischen Methode nicht verloren geht.

Zum Nachstellen dieses Sachverhalts wollen wir in unserer nicht-statischen init-Methode der Klasse MfgDemo eine neue nicht-statische Methode startDemoLoop aufrufen. Sie ruft alle zehn Millisekunden die nicht-statische Methode tick auf.

Damit der Objektkontext innerhalb der nicht-statischen Methode tick erhalten bleibt, muss die Signatur dieser nicht-statischen Methode die Arrow Syntax beinhalten:

In der Konsole des Browsers wird nun this als korrekte Instanz der Klasse MfgDemo angezeigt.

Wird die Arrow-Syntax testweise weggelassen, so wird this fälschlicherweise als Instanz des globalen Window-Kontexts interpretiert, sodass ein Zugriff auf das nicht-statische Feld items an dieser Stelle scheitert und somit als undefined zurückgegeben wird!

18. Verwenden von Foreach-Schleifen

Hiermit können wir komfortabel über alle Elemente von Arrays und anderen Collections iterieren. Als Beispiel können wir die Position all unserer Rechtecke verändern und anschließend alle Rechtecke auf die Zeichenfläche zeichnen.

Wir rufen hierfür zwei separate, nicht-statische Methoden innerhalb unserer nicht-statischen Methode tick auf. Der zuvor testweise eingesetzte Konsolenbefehl kann in diesem Schritt wieder entfernt werden.

Anschließend sehen wir unterschiedliche Rechtecke auf unserer Zeichenfläche, die allesamt langsam absteigen (Abb. 10).

19. Einbinden externer Bibliotheken

Zu guter Letzt wollen wir eine externe JavaScript-Bibliothek einbinden und in unserem Code typisiert verwenden.
In unserem Beispiel wollen wir die JavaScript-Bibliothek FPSMeter einbinden, mit der wir die Frames Per Second unserer Demo gemessen und angezeigt bekommen.


Bitte beachten!

Das manuelle Einbinden externer JavaScript-Bibliotheken und TypeScript Definition-Files ist deprecated! Die korrekte Einbindung externer Bibliotheken erfolgt durch den Einsatz des Node Package Managers. Das Herunterladen der JavaScript-Bibliothek und der zugehörigen Type-Definition-Dateien kann für die Erweiterung „FPSMeter“ beispielsweise mit Hilfe der folgenden Befehlen erfolgen:

Da die Verwendung des Node Package Managers den Rahmen dieses Workshops an dieser Stelle sprengen würde, erfolgt die Einbindung in unserem Projekt daher manuell.


Die Einbindung einer externen Bibliothek erfolgt in drei Schritten:

19.1. Einbinden der JavaScript-Datei der Bibliothek

Die JavaScript-Datei der Erweiterung FPSMeter kann in vollständiger oder auch in minifizierter Version eingebunden werden. Die aktuelle Version der Bibliothek FPSMeter kann von der Webseite der Erweiterung heruntergeladen werden.

In unserer Demo legen wir die Datei unter js/lib/fpsmeter-0.3.1.min.js ab. Damit der Browser sie laden kann, müssen wir die Datei in unserer index.html referenzieren. Daher erweitern wir das Tag unserer Webseite um das folgende Script-Tag:

19.2. Einbinden der Type-Definition-Datei der Bibliothek

Damit der TypeScript-Compiler die Typisierung der externen JavaScript-Bibliothek handhaben kann, muss eine sogenannte Type-Definition-Datei zu unseren zu kompilierenden TypeScript-Quellcodes hinzugefügt werden.

Die Seite definitelytyped.org versteht sich als Repository aller wichtigen Type-Definition-Dateien für alle wichtigen JavaScript-Bibliotheken. Für das FPSMeter befindet sich die entsprechende Type-Definition-Datei auf GitHub.

Wir können diese Datei an einem beliebigen Ort unterhalb unseres Verzeichnisses src/ ablegen, damit der TypeScript-Compiler die Struktur der Bibliothek erkennen kann. Unserem Schema im Dateisystem folgend sollte die Datei unter src/lib/FPSMeter.0.3.0.d.ts abgelegt werden.

19.3. Einbau der Erweiterung in den Code

Eine Instanz der Klasse FPSMeter soll nun in unserer Klasse MfgDemo in einem nicht-statisches Feld festgehalten werden. In unserer nicht-statischen Methode init instanziieren wir die Klasse FPSMeter, und in unserer nicht-statischen Methode tick teilen wir dem FPS-Meter mit, wann der aktuelle Tick beginnt und wann er endet.

Anschließend wird das FPS-Meter in der unteren rechten Ecke unserer Webseite angezeigt (Abb. 11).

Da wir einen konstanten Wert von 10ms als Verzögerung zwischen unseren Ticks definiert haben, sollte der FPS-Counter permanent 100 Frames pro Sekunde anzeigen. Interessanter wird die Verwendung dieser Erweiterung natürlich erst, wenn aufwändigere Rechen- und Zeichenoperationen – beispielsweise unter Verwendung einer 3D-Zeichenfläche – durchgeführt werden und somit ein Schwanken dieses FPS-Wertes beobachtet werden kann.

Abschluss

TypeScript stellt eine praktische Alternative zu JavaScript dar, mit der auch das Umschreiben bestehender JavaScript-Projekte nach TypeScript nahtlos möglich ist.

Ich möchte jedem Entwickler die Einführung von TypeScript sehr an Herz legen, da diese einen großen Gewinn für jedes JavaScript-Projekt darstellt.

Den Projektcode des TypeScript-Workshops findet man übrigens auf GitHub. Und wenn Du Dich noch tiefer mit dem Thema beschäftigen möchtest, findet am 27. Juni ein TypeScript-Workshop in Berlin statt.

Dieser Eintrag wurde veröffentlicht in Development, JavaScript und verschlagwortet mit , , von Christopher Stock. Permanenter Link zum Eintrag.

Über Christopher Stock

Christopher ist als Senior Developer bei der Mayflower GmbH tätig und entwickelt dort hochwertige Web-Applikationen, unter anderem mit Java, TypeScript und PHP. Zu seinen Hobbys gehören neben der Programmierung auch Designen, Joggen, Skifahren, Schwimmen, Fitness und Verreisen. Trotz mehr als 15 Jahren Berufserfahrung als Softwareentwickler im Web-, Desktop- und Mobile Application-Bereich liebt er die Programmierung noch immer wie bei seinem allerersten GW-BASIC Programm.

Für neue Blogupdates anmelden:


2 Gedanken zu “TypeScript-Workshop

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.