TypeScript (Teil 1/2): die Fakten

n

nMicrosoft hat TypeScript veröffentlicht, laut offizieller Ansage eine Programmiersprache for application-scale JavaScript development. Meiner Wahrnehmung nach wurde TypeScript in der Webentwickler-Welt mit einer gewissen Skepsis aufgenommen, was ich spontan durchaus nachvollziehbar finde – immerhin ist es eine Technologie für das Web von Microsoft und das kollektive Gedächtnis der Webentwickler vergisst kleine Sünden wie den IE6 und andere Untaten nicht so schnell.n

nAber da ich es in meinen HTML5-Seminaren immer öfter mit Entwicklern aus der Microsoft-Ecke zu tun habe, komme ich nicht umhin, mir TypeScript mal vorurteilsfrei reinzuziehen, denn irgendwer wird bestimmt mal danach fragen. Das Reinziehen ist gar nicht mal so trivial, denn leider versteckt die die offizielle Webseite viele nützliche Informationen zugunsten von eher Marketing-fokussierter Prosa (auf deren Inhalt sich dann auch die meisten der hämischen Kommentare beziehen). Ich habe es aber trotzdem mal anhand der Specs versucht. In diesem ersten Teil will ich versuchen, die wichtigsten Fakten rund um TypeScript herauszuarbeiten, mein Kommentar zu dem Ganzen folgt dann in einem zweiten Artikel.nn

Was ist TypeScript?

n

nTypeScript ist ein Superset von JavaScript – jedes gültige JavaScript-Programm ist auch ein (syntaktisch) gültiges TypeScript-Programm. Die Erweiterungen von TS werden vom Compiler in stinknormales JavaScript umgewandelt, so dass man TypeScript mit jedem Browser der Welt oder auch mit Node.js benutzen kann, solange man es vorher kompiliert. Der Vergleich mit Googles ungleich ambitionierterem Dart ist also weniger zutreffend als z.B. mit CoffeeScript. Bei Dart ist die JavaScript-Kompilierung nur eine Krücke, bei TypeScript das Endziel.n

nDie Features, die TypeScript neu einführt, fallen in zwei Kategorien: einerseits gibt es ein optionales Typsystem, andererseits sind mehrere Funktionen aus ECMAScript 6 übernommen worden. Das Typsystem erlaubt es, Variablen fest einen Typ zuzuweisen. Diese Information können Compiler und IDEs benutzen, um Fehler zu schmeißen bzw. bessere Autovervollständigung anzubieten. Die ES6-Features ermöglichen es, so zu programmieren, als sei der neue JavaScript-Standard (bzw. Teile davon) bereits fertig und in allen Browsern zu finden. Das Endprodukt ist trotz all dieser Features immer komplett normales JS, so wie man es auch händisch schreiben würde. Selbst wenn man volles Rohr auf TS-Features setzt …n

class Auto {n  private kilometer: number = 0;n  constructor(public modell, public baujahr){}n  public fahren(km: number){n    this.kilometer += km;n  }n  public getKilometer(){n    return this.kilometer;n  }n}nninterface Fahrzeug {n  modell: string;n  baujahr: number;n  getKilometer: () => {};n}nnvar karre = new Auto('VW Käfer', 1984);nkarre.fahren(20);nnfunction describe(auto: Fahrzeug) {n  return "Ein " + auto.baujahr + "er " + auto.modell +n         " mit " + auto.getKilometer() + "km auf der Uhr";n}

n

n… ist das Endprodukt so normales JavaScript, dass es selbst im IE6 laufen würde:n

var Auto = (function () {n    function Auto(modell, baujahr) {n        this.modell = modell;n        this.baujahr = baujahr;n        this.kilometer = 0;n    }n    Auto.prototype.fahren = function (km) {n        this.kilometer += km;n    };n    Auto.prototype.getKilometer = function () {n        return this.kilometer;n    };n    return Auto;n})();nvar karre = new Auto('VW Käfer', 1984);nkarre.fahren(20);nfunction describe(auto) {n    return "Ein " + auto.baujahr + "er " + auto.modell + " mit " + auto.getKilometer() + "km auf der Uhr";n}

n

nWas also ist Typescript? Es ist kein Dart, sondern eigentlich nur ein JavaScript-Dialekt, dessen Compiler ein Typsystem und einen ES6-Transpiler implementiert und dessen Endprodukt stinknormales JavaScript ist.nn

How to Typescript

n

nDer TypeScript-Compiler ist (natürlich) in TypeScript geschrieben und fluppt daher in jeder handelsüblichen JavaScript-Umgebung. Als Open-Source-Software (Apache License) lässt sich das gute Stück entweder über CodePlex (eine Art Github für MS) oder via npm install -g typescript in Node.js beschaffen. Die Datei foo.ts kompiliert man dann durch den Aufruf tsc foo.ts und erhält dafür die Datei foo.js.n

nAls Tools gibt es neben dem Plugin für Visual Studio 2012 auch Erweiterungen für Vim, Emacs und Sublime Text 2. Darüber hinaus existiert auch eine Online-Sandbox.nn

Das Typsystem

n

nJavaScript ist eine Sprache mit einem schwachen, dynamischen Typsystem. Das lässt sich komödiantisch ausschlachten (ab 01:20), hat aber primär den Effekt, dass ein JS-Programmierer dem Interpreter weder vorbeten muss, welche Datentypen gewisse Objekte haben noch sich manuell um deren ggf. nötige Umwandlung kümmern muss. Die JS-Engine erkennt die Art der verwendeten Datentypen selbstständig (Duck Typing) und wenn zwei Objekte unterschiedlichen Typs aufeinander treffen, wird einer der beiden Unfallgegner automatisch konvertiert:n

// Das sieht wie ein String ausnvar s = "Hallo Welt";nn// Das sieht wie eine Zahl ausnvar n = 1337;nn// String plus Zahl geht nicht, also wird die Zahln// gemäß der JS-Regeln vor der Operation umgewandeltnvar x = s + n;  // Ergibt den String "Hallo Welt1337"

n

nDieses Feature lässt allerdings nicht wenigen Programmieren die Haare zu Berge stehen. Einerseits befürchten sie, dass bei versehentlichen Typumwandlungen schwer zu diagnostizierende Bugs entstehen und sie hätten es lieber, wenn bei der Kollision zweier Typen ein Fehler gemeldet wird. Andererseits soll ein dynamisches Typsystem auch die Entwicklung von IDEs mit intelligenter Autovervollständigung und anderen fortschrittlichen Funktionen schwerer machen. Als Antwort auf diese Bedenken führt TypeScript ein statisches Typsystem ein, das alle Wünsche der Haare-zu-Berge-Fraktion erfüllt.n

nIn TypeScript-Code kann bei Variablen angegeben werden, welchen Typ sie haben sollen:n

// Ein Stringnvar s: string = "Hallo Welt";nn// Eine Zahlnvar n: number = 1337;

n

nDiese Typannotationen sind optional. Fehlen sie, findet der TS-Compiler selbst heraus, welchen Datentyp ein Objekt hat (Typinferenz). Sinn des Ganzen ist, dass Tools (und Entwickler) sofort erkennen können, welche Sorte von Objekt in einer Variable vorkommen sollte und der Compiler kann Alarm schlagen, wenn diese Regeln mißachtet werden:n

// Der Compiler meldet: "Cannot convert 'number' to 'string'"nvar s: string;ns = 42;nn// Der Compiler meldet: "Supplied parameters do not match any signature of call target"nfunction sagHallo(name: string){n  return "Hallo " + name;n}nsagHallo(42);

n

nDas Ganze funktioniert einerseits mit den aus JS bekannten Primitiven (String, Number usw.), kann aber auch auf Objekte angewendet werden. So lässt sich zum Beispiel ein Array definieren, das nur Strings enthalten darf:n

var arr: string[] = [];

n

nFür Eigenbau-Objekte lässt sich ein Interface definieren, dass festlegt, wie ein Objekt aufgebaut sein muss:n

interface Fahrzeug {n  modell: string;n  baujahr: number;n}nnfunction describe(auto: Fahrzeug) {n  return "Ein " + auto.baujahr + "er " + auto.modell;n}nndescribe({n  modell: 'Käfer',n  baujahr: 1970n});

n

nAuch Funktionen können als Typ angegeben werden … mitsamt der Argumente, die die Funktion übergeben bekommen soll. Das erscheint besonders bei Callbacks sinnvoll:n

function fireCb(callback: (i: number) => {}){n  for(var i = 0; i < 5; i++){n    callback(i);n  }n}nn// KlapptnfireCb(function(i){n  console.log(i);n});nn// Klappt nicht, da das Argument "foo" nicht gewünscht istn// Supplied parameters do not match any signature of call target:n// Call signatures of types '(i: any,foo: any) => any' and '(i: number) => {}' are incompatible:n// Call signature expects 1 or fewer parametersnfireCb(function(i, foo){n  console.log(i);n});

n

nIn diesem Code fällt der etwas befremdlich aussehende Schnipsel (i: number) => {} ins Auge. Dabei handelt es sich um eine neue Schreibweise für Funktionen, die in ECMAScript 6 eingeführt werden soll und die in Typescript bereits unterstützt wird.nnnn

Die ES6-Features

n

nECMAScript 6 ist die kommende Ausbaustufe von JavaScript (zu der ich rein zufällig eine Artikelserie parat habe) und befindet sich in einem Zustand höchster Unfertigkeit. Ungeachtet dessen gibt es bereits einige Programme, die ES6-Code in heute schon funktionierendes JavaScript übersetzen – die sogenannten Transpiler. Auch in TypeScript steckt ein solcher Transpiler und manches ES6-Feature kann hier schon benutzt werden.n

nDie etwas komisch aussehende Funktionssystax entspringt (das ist kein Witz) primär dem Wunsch, nicht mehr das lange Wort function ausschreiben zu müssen. Und wenn man schon dabei ist, könnte man die neue Form doch auch gleich mit einem besonderen Scope-Binding ausstatten. So ging man also hin, borgte sich von CoffeeScript den fat arrow und schon war man fertig:n

var fn = () => {n  console.log(this.foo);n};nn// Entspricht (und kompiliert in TypeScript zu):nnvar _this = this;nvar fn = function () {n  console.log(_this.foo);n};

n

nEbenfalls in ES6 geplant und in Typescript umgesetzt ist ein Klassensystem, das zwar recht simpel ist, aber grundsätzlich alles an Bord hat, was man so erwarten würde:n

class Auto {n  private kilometer: number = 0;n  constructor(public modell: string, public baujahr: number){}n  public fahren(km: number){n    this.kilometer += km;n  }n  public getKilometer(){n    return this.kilometer;n  }n}nnvar karre = new Auto('VW Käfer', 1984);nkarre.fahren(20);nvar tacho = karre.getKilometer(); // 20

n

nDer Code, den der Typescript-Compiler hieraus erzeugt, ist eine relativ simple Constructorfunktion nebst Prototype, bei dem die private-Properties nicht besonders (z.b. durch Closure-Versteckspiele) geschützt sind:n

var Auto = (function () {n    function Auto(modell, baujahr) {n        this.modell = modell;n        this.baujahr = baujahr;n        this.kilometer = 0;n    }n    Auto.prototype.fahren = function (km) {n        this.kilometer += km;n    };n    Auto.prototype.getKilometer = function () {n        return this.kilometer;n    };n    return Auto;n})();

n

nAllein der Compiler verhindert, dass ein direkter Zugriff auf private Objekte wie karre.kilometer erfolgt.n

nWer Klassen haben will, möchte diese vermutlich auch in Modulen organisieren natürlich haben ES6 und TypeScript entsprechende Funktionalität an Bord:n

// modul.tsnexport class Auto {n  private kilometer: number = 0;n  constructor(public modell: string, public baujahr: number){}n  public fahren(km: number){n    this.kilometer += km;n  }n  public getKilometer(){n    return this.kilometer;n  }n}nn// main.tsnimport fahrzeug = module("modul");nvar karre = new fahrzeug.Auto('VW Auto', 1984);nkarre.fahren(20);

n

nDer Compiler baut aus modul.ts wahlweise CommonJS-Module für den Einsatz in Node.js und anderen serverseitigen Umgebungen …n

var Auto = (function () {n    function Auto(modell, baujahr) {n        this.modell = modell;n        this.baujahr = baujahr;n        this.kilometer = 0;n    }n    Auto.prototype.fahren = function (km) {n        this.kilometer += km;n    };n    Auto.prototype.getKilometer = function () {n        return this.kilometer;n    };n    return Auto;n})();nexports.Auto = Auto;

n

n… oder AMD-Module für RequireJS und Konsorten:n

define(["require", "exports"], function(require, exports) {n    var Auto = (function () {n        function Auto(modell, baujahr) {n            this.modell = modell;n            this.baujahr = baujahr;n            this.kilometer = 0;n        }n        Auto.prototype.fahren = function (km) {n            this.kilometer += km;n        };n        Auto.prototype.getKilometer = function () {n            return this.kilometer;n        };n        return Auto;n    })();n    exports.Auto = Auto;n});

n

nWenn eines Tages ES6-Module wie geplant Einzug in die JavaScript-Engines dieser Welt finden, wird diese Übersetzung dann vermutlich überflüssig.nn

Fazit

n

nZusammengefasst ist TypeScript also ein JavaScript-Superset, das JS um Features aus der ECMAScript-Zukunft sowie ein eigenes Typsystem erweitert. Da all diese Features ausschließlich im Compiler stattfinden und das Endprodukt normales JavaScript ist, sind keine Browser-Updates oder Polyfill-Scripts nötig um mit TS loszulegen.n

nDie Preisfrage ist nun: braucht man das? Wenn ja, wer braucht das? Will man das überhaupt in der JavaScript-Welt herumgeistern sehen? Und wird TypeScript eine Nutzerschaft finden oder in der Bedeutungslosigkeit versinken? Meine Meinung dazu gibt es die Tage in Teil 2.


Kommentare

Schreibe einen Kommentar

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