Ein Streifzug durch die Features von TypeScript
In den letzten Jahren hat sich die Entwicklung von Web-Anwendungen in eine Richtung gedreht, in der immer größere Teile komplexer Softwaresysteme im Browser leben. Damit haben sich auch die Ansprüche an den Browser als Softwareplattform geändert, und die Kapselungs- und Abstraktionsmöglichkeiten der ehemals als HTML-Erweiterung angelegten Browser-Programmiersprache JavaScript genügen nicht mehr.
Inzwischen gibt es eine Reihe von Programmiersprachen, die mit unterschiedlichen Ansätzen an JavaScript andocken können. In einem Artikel über ClojureScript wurde in diesem Blog bereits eine Sprache aus der LISP-Familie vorgestellt. Im vorliegenden Artikel geht es um TypeScript, eine Alternative, die sich durch ein statisches, von C# inspiriertes Typsystem und niedrige Einsatzhürden auszeichnet.
TypeScript ist eine Obermenge von JavaScript, d.h. jedes JavaScript-Programm ist ein TypeScript-Programm. So kann der Compiler mit wenigen Stunden Aufwand selbst in ein großes Softwareprojekt eingeführt werden, (fast) ohne den Code zu ändern. Die Vorteile der statischen Typisierung kann man dann nach und nach intensiver nutzen. Die Neuerungen an TypeScript sind konservativ und orientieren sich an bestehenden Sprachen wie C# (das Projekt stammt aus dem Hause Microsoft) und Java.
Wie JavaScript hat TypeScript Funktionen erster Klasse (Funktionen sind Daten) und höherer Ordnung (Funkionen können andere Funkionen als Parameter nehmen), und kann damit der Familie der Funktionalen Programmiersprachen zugeordnet werden.
Der Compiler ist in TypeScript geschrieben, läuft in Node.js, und lässt sich genauso gut in CLI-basierte Entwicklungsumgebungen oder emacs integrieren wie in Eclipse oder VisualStudio. Es unterstützt die gängigen JavaScript-Modulsysteme und skaliert gut in großen Softwareprojekten. Ich will im Folgenden zunächst die Sprache vorstellen und versuchen, ein Gefühl zu dafür geben, was es heißt, in TypeScript zu denken. Ein Abschnitt über Entwicklungswerkzeuge und das Arbeiten mit TypeScript-Code folgt danach.
Dem eiligen Leser, der sowohl in JavaScript als auch in C#, Java o.ä. Routine hat, mag es genügen, die Code-Schnipsel zu lesen und den erklärenden Text auszulassen.
Fehler finden in JavaScript
TypeScript bietet einen Spielplatz (hier ohne SSL) im Netz an, auf dem Code-Schnipsel nach JavaScript übersetzt und ausgeführt werden können. Zum besseren Verständnis können Sie die folgenden Beispiele wärend des Lesens hier eingeben und mit den Übersetzungen zu vergleichen. Hier als erstes Beispiel ein einfaches „Hello-World“-Programm:
So sollte das im Playground aussehen:
Zunächst fällt auf, wie durchlässig die Abstraktionsschicht zwischen Quell- und der Zielsprache ist. Jedes JavaScript-Programm ist ein TypeScript-Programm; Wenn man also einfachen JavaScript-Code in das TypeScript-Feld auf der linken Bildhälfte eingibt, tut der Compiler (fast) gar nichts. Auf der rechten Bildhälfte im generierten JavaScript-Code sieht man, dass in der zweiten Zeile ein Semikolon angehängt wurde; ansonsten bleibt der Code unverändert.
Dabei hat TypeScript bereits einiges geleistet: Für jeden Ausdruck im
Quellcode wurde automatisch ein statischer Typ hergeleitet und die
Korrektheit des gesamten Programms (bezüglich dieser Typen)
festgestellt. Außerdem wurden die Typen in den Playground gereicht,
wo man sie sich anzeigen lassen kann, in dem man mit der Maus auf
einen Ausdruck zeigt (msg
hat etwa den Typ string
).
Auch beim Debugging leistet der Compiler bereits gute Dienste, ohne auf Sprach-Erweiterungen zuzugreifen. Wenn man den folgenden Code in den Playground eingibt:
… werden zwei Stellen rot unterstrichen, und durch Berührung mit der Maus kann man sich die Fehler anzeigen lassen:
',' expected.
Und, nachdem das anstößige ;
entfernt oder durch ein ,
ersetzt
ist, der Buchstabendreher in header
:
The property 'haeder' does not exist on value of type
'{ header: string; details: string[]; }'.
Für den Entwickleralltag bedeutet das eine enorme Verbesserung: Statt den Code in den Browser oder in node-js zu laden und eine Unit-Testsuite auszuführen, um Tipp- und Syntaxfehler zu finden, kann man nun im Editor auf Knopfdruck auf den nächsten Tippfehler gesetzt werden. (Dazu später mehr.)
Typen zur Dokumentation von JavaScript-Code
Ein Typsystem ist eine Meta-Sprache, in der Aussagen über die Struktur einer darunterliegenden Programmiersprache gemacht werden können. Das Typsystem von TypeScript ist also eine Sprache, in der man über JavaScript reden kann.
Wie wir bisher gesehen haben, kann der TypeScript-Compiler dies bis zu einem gewissen grad tun, ohne uns damit zu behelligen (es sei denn natürlich, es gibt Typfehler zu berichten). In der Praxis interessant wird es aber erst, wenn wir die Typ-Sprache in Form von Annotationen verwenden können, um dem Compiler unseren Code genauer zu erklären. Dadurch erhält man nicht nur die Garantie, dass zur Laufzeit eine große Klasse von Fehlern nicht mehr auftreten kann, sondern man bekommt quasi kostenlos maschinell verifizierte Quellcode-Dokumentation.
Typ-Annotationen in TypeScript können an jeder Stelle stehen,
an der ein Name definiert wird, und werden mit :
eingeleitet:
Anders als die JavaScript-Typen, die zur Laufzeit mit typeof
abgefragt werden können, existieren die Typ-Annotationen von
TypeScript nur in der Übersetzungsphase, wo sie der
Korrektheitsanalyse dienen. Der JavaScript-Code enthält keine Spur
mehr von : string
:
(Wenn ich im zweiten Teil dieses Artikels auf Interfaces und Klassen eingegangen bin, wird klar werden, warum man TypeScript-Typen zur Laufzeit behalten möchte.)
Neben den einfachen Basistypen string
, number
, und boolean
, gibt
es Typen für Funktionen und (natürlich) Objekte und Arrays:
Der aufmerksame Leser hat vielleicht bemerkt, dass die Implementierung
von f
in ein eigenes Statement gerutscht ist. Das liegt daran, dass
der Typ ((number, string) => string)
im Gegensatz zu string
nicht
in Typ-Annotationen direkt verwendet werden kann. Das ist eine
seltsame Ausnahme und ein Bruch mit der Idee der funktionalen
Programmierung, aber glücklicherweise gibt es eine spezielle
Schreibweise, die ohnehin besser zu lesen ist:
Im zweiten Teil dieses Artikels werden wir mehr über Funktionen, Typen, Klassen und Module lernen.
An dieser Stelle sei nur noch angemerkt, dass auch die etwas klobige
Typ-Annotation von msg
im letzten Beispiel eleganter ausgedrückt
werden kann. Objekt-Typen kann man nämlich wie JavaScript-Ausdrücke
einem Namen zuweisen:
Installation und Benutzung
Um den TypeScript-Compiler unter Linux zu installieren, benötigt man node und npm. Beides ist in allen verbreiteten Distributionen enthalten. Wer sicher gehen will, dass er die aktuellste Version hat, kann direkt von der Website installieren:
Danach ist die Installation von TypeScript ein Kinderspiel:
TypeScript wird in vielen IDEs unterstützt (insbesondere Eclipse und VisualStudio). Aber auch wer emacs, vi, gmake etc. als IDE verwendet, findet sich schnell zurecht:
Der entstehende JavaScript-Code kann nun genau wie der von Hand geschriebene in den Browser eingebunden werden.
tsc
hat ein eigenes Format für Zeilen- und Spaltennummern in
Fehlermeldungen. Wer die einzeiligen Fehlmeldungsbandwürmer nicht mag
oder seine IDE schon auf den de-Facto-Standard von gcc
eingerichtet
hat, kann sich mit perl
die Fehlermeldung umformatieren:
tsc
lässt sich übrigens auch im „watch“-Modus betreiben:
Nun können Sie code.ts
im Editor bearbeiten, und bei jedem Schreiben
wird tsc
die Datei neu übersetzen und ggf. Fehler ausgeben:
Stay tuned…
Auf einige unbehandelte Themen möchte ich zum Abschluss nur kurz verlinken:
- sourceMaps, mit denen der Browser den TypeScript-Quellcode im debugger anzeigen kann, während er im Hintergrund durch die korrespondierenden Zeilen im generierten JavaScript-Code läuft;
- Integration mit den üblichen Modulsystemen requirejs/amd und commonjs;
- eine Bibliothek von Interfaces mit einer langen Liste von JavaScript-Bibliotheken und Frameworks, mit denen Typfehler in Aufrufen in diese Bibliotheken beim Übersetzen abgefangen werden können;
- tslint für weitergehende Coding-Policy-Checks.
Der zweite Teil dieses Artikels erscheint in den nächsten Wochen. Dort werde ich auf fortgeschrittenere und Abstraktionswerkzeuge in TypeScript eingehen und sprachliche Feinheiten und Designentscheidungen diskutieren.