Warum Typescript?
Angular-Apps werden typischerweise mit Typescript entwickelt, Angular selber ist mit Typescript implementiert. Aber warum muss ich eine neue Sprache lernen um mit Angular zu entwickeln? Keine Angst, es ist nicht wirklich eine neue Sprache. Typescript ist eine Obermenge von Javascript, jeder ES6-Code ist damit valider Typescript-Code. Ein Umbenennen von .js-Dateien zu der Typescript Dateiendung .ts ist also ohne weiteres möglich. Die Typescript-Erweiterungen werden vom Compiler in gültiges Javascript umgewandelt, das im Browser oder per node.js ausgeführt werden kann.
Jeder der schon mal mit Javascript gearbeitet hat, wird sich schnell mit Typescript anfreunden. Typescript bietet schon jetzt Features die in dem kommenden ECMAScript-Standards (ES6/7) enthalten sein werden. Wer auf Browserkompabilität achten und Browser unterstützen muss die noch kein ES6 können, kann als Zieltarget für den Transpiler ebenso ES5 angeben. Dann wird vom Typescript-Transpiler ES5 kompatibler Javascript-Code erzeugt. Dazu später mehr.
Will man direkt Angular-Komponenten mit Javascript nach ES5 entwickeln, ist auch das möglich. Es gibt eine API die vollen Zugriff auf die Angular-Funktionalität zur Verfügung stellt. Aber warum sollte ich dann trotzdem Typescript benutzen? Welchen Mehrwert habe ich davon? Ganz einfach. Typescript bietet eine Menge Features die das Programmierleben erheblich vereinfachen 🙂 Folgende Verbesserungen gegenüber ES5 stellt Typescript zur Verfügung.
- Typen
- Klassen
- Interfaces
- Annotations
- Imports
- Arrow Funktionssyntax =>
- Block-Scope Variablen mit let
- Konstanten mit const
Den grössten Mehrwert gegenüber ES5 stellt das Typsystem von Typescript dar. Dadurch können Fehler schon während der Compilerzeit entdeckt werden und der Code wird klarer und leichter verständlich. Dadurch werden ebenso Refactorings einfacher und die Codequalität erhöht.
Im folgenden gebe ich eine Vorstellung der Features von Typescript. Wer tiefer einsteigen möchte, dem empfehle ich das Online-Buch Typescript Deep Dive von Basarat Ali Syed
Typescript wird per npm installiert
npm install -g typescript
Ein
tsc -v
sollte nun die aktuelle Typescriptversion liefern.
Als Entwicklungsumgebung kann jeder beliebige Editor dienen. Will man etwas mehr Komfort wie Syntaxhighlightning, Codevervollständigung usw. nimmt man einen Editor mit Typescriptunterstützung. Empfehlen kann ich folgende IDEs:
So jetzt wollen wir aber mal ein bisschen Code schreiben 😉 Eine Variablendeklaration in Typescript sieht folgendermassen aus:
var name: string;
Mit let werden Variablen blockscope deklariert, wie man es auch von anderen Sprachen kennt.
let name: string;
Typen können in Funktionen als Parameter und Rückgabewerte verwendet werden:
function greetTo(name: string): string { return "Hello" + name; }
Wird die Function mit einem falschen Typparameter aufgerufen, oder wird ein falscher Wert zurückgegeben, wirft der Compiler einen Fehler. Dadurch werden Fehler im Vorfeld vermieden.
Typescript-Dateien werden, wie oben schon erwähnt, mit der Endung .ts angelegt. Um ein einfaches Beispiel zu erzeugen legt man am Besten einen Ordner an, z.B. hello-world-typescript, und darunter den typischen src-Folder in dem die Source-Datei(en) angelegt werden.
mkdir -p hello-world-typescript/src Dann wird die Datei tsconfig.json mit folgenden Inhalt im Hauptverzeichnis erzeugt:
{ "compilerOptions": { "target": "es5" } }
Diese Datei enthält die Konfiguration für den Typescript-Compiler. Als Target wollen wir ES5 kompatiblen Javascript-Code erzeugen.
Im src-ordner legen wir nun die Datei app.ts für unser Helloworld-Beispiel an.
Darin schreiben wir folgenden Inhalt:
function greetTo(name: string): string { return "Hello" + name; } console.log(greetTo("Typescript"));
Dann wird der Compiler-Lauf mit folgenden Befehl angestossen:
tsc -p .
Mit -p stellen wir sicher das die lokale tsconfig.json verwendet wird. Als Ergebnis des Laufs sollte im src-Ordner eine Datei app.js vorhanden sein, die den kompilierten Javascript-Code enthält. Wenn wir die Datei öffnen fällt auf das der Code, bis auf die Typenformationen, identisch ist. Das heisst der Typescript-Compiler entfernt alle Typinformationen.
function greetTo(name) { return "Hello" + name; } console.log(greetTo("Typescript"));
Mit node.js können wir den generierten Javascript ausführen
node src/app.js
Die Ausgabe sollte auf der Console erscheinen.
Wen wir nun einen Fehler einbauen, z.B. einen falschen Typ an die Funktion übergeben, sollte der Compiler einen Fehler werfen:
function greetTo(name: string): string { return "Hello " + name; } console.log(greetTo(3));
tsc -p . src/app.ts(5,26): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
Interessanterweise wird trotzdem eine Javascript-Datei erzeugt. Wenn man diese ausführt, erhält man folgende Ausgabe
node src/app.js Hello 3
Dieses Verhalten kann ändern in dem man das Property
"noEmitOnError": true
in der tsconfig.json setzt. Dadurch wird keine Javascript-Datei bei einem Compiler-Fehler erzeugt.
Typescript, bringt, wie ES6, den FatArrow- Operator mit. Damit lassen sich Funktionsdeklarationen wie folgt schreiben:
var foo: String = "Hello"; var fn = () => { console.log(this.foo); };
Der Compiler generiert daraus folgendes Javascript
var _this = this; var foo = "Hello"; var fn = function () { console.log(_this.foo); };
Wie man sieht wird this entsprechend an den umgebenden Kontext gebunden.
Erweitern wir das Beispiel um ein Interface.
interface Person { firstName: string; lastName: string; } function greetTo(person: Person): string { return "Hello " + person.firstName + " " + person.lastName; } var person = { firstName: "Tony", lastName: "Stark"}; console.log(greetTo(person));
Ein Interface beschreibt wie ein Objekt aufgebaut ist, es handelt sich also um ein strukturelles Interface. Das Objekt kann ohne Konstruktor erzeugt werden, es muss lediglich ein Objekt mit der Struktur des Interfaces definiert werden. Typescript führt ebenso ein Klassensystem ein mit denen man Objekte definieren kann. Als Klasse sieht obiges Beispiel so aus:
class Person { constructor (public firstName: string, public lastName: string) { } public greetTo(): string { return "Hello " + this.firstName + " " + this.lastName; } } let tony: Person = new Person ("Tony", "Stark"); console.log(tony.greetTo());
Wenn wir diese Klasse in andere Komponenten nutzen wollen können wir sie exportieren:
export class Person { ... } // die exportierte Klasse können wir mit einem import in anderen Dateien einbinden // main.ts import { Person } from "./app2"; let anotherHero: Person = new Person("Barry", "Allen"); console.log(anotherHero.greetTo());
So, das soll an dieser Stelle erstmal reichen für einen Schnelleinstieg in Typescript. Wer tiefer einsteigen möchte sollte sich das oben erwähnte Buch Typescript Deep Dive von Basarat Ali Syed ansehen.