Neue Kolumne: Keine Angst vor JavaScript!

Wer hat das beste Typensystem? JavaScript!

Nils Hartmann, Oliver Zeigermann

Oliver Zeigermann & Nils Hartmann

In dieser Kolumne zeigen Ihnen Nils Hartmann und Oliver Zeigermann, wie Sie ein ganz entspanntes Verhältnis zum Thema JavaScript-Entwicklung bekommen können und dass das Arbeiten mit JavaScript sogar Spaß machen kann! Sie betrachten dabei nicht nur die Sprache, sondern werden auch einen Überblick über Frameworks, Tools und Methoden ansehen, die im JavaScript-Universum eine Rolle spielen.

Wer hat das beste Typensystem? JavaScript!

Sollte das tatsächlich möglich sein? Gibt es für JavaScript ein Typensystem, das dem von Java oder C# ebenbürtig ist? Nein! Es ist den Typensystemen von Java oder C# in mancher Hinsicht sogar überlegen. Hier sehen Sie, warum!

Keine Angst vor JavaScript

Keine_Angst_vor_JavaScriptIn der Kolumne „Keine Angst vor JavaScript!“ zeigen Nils Hartmann und Oliver Zeigermann, wie man ein ganz entspanntes Verhältnis zum Thema JavaScript-Entwicklung bekommt – und dass das Arbeiten mit JavaScript sogar Spaß machen kann!

Wir betrachten dabei nicht nur die Sprache, sondern werden uns auch einen Überblick über Frameworks, Tools und Methoden ansehen, die im JavaScript-Universum eine Rolle spielen.

Bisher erschienen:

Zuerst einmal: So ganz stimmt das natürlich nicht. Das Typensystem von JavaScript existiert nur zur Laufzeit und kann mit dem von Java, C# oder auch C++ allein schon deshalb nicht konkurrieren. Aber: Es gibt zumindest ein Typensystem für JavaScript! Und zwar eines, das es mit allen aufnehmen kann: TypeScript, das von Microsoft entwickelt wird. Unter anderem in Person von Anders Hejlsberg, der auch schon Turbo Pascal entwickelt und an C# mitgewirkt hat. Und TypeScript ist kein Spielkram!

Googles Angular 2 wurde ebenso wie Microsofts Entwicklungsumgebung Visual Studio Code komplett in TypeScript geschrieben. Beides sind Beispiele großer und komplexer Code-Basen, die durch TypeScript handhabbar geblieben sind.

TypeScript enthält im wesentlichen ECMAScript 2015 (also die aktuelle Version von JavaScript) sowie einigen Erweiterungen:

  1. Access-Modifier für Klassen, also public, private, protected
  2. Ein Typensystem mit optionalen Typinformationen

Damit können Sie schon einmal alle grundlegenden Sachen mit Typen ausdrücken, wie eben auch in Java oder C#. Allerdings müssen Sie nicht überall Typinformationen hinschreiben, fehlende Informationen werden vom TypeScript Compiler so gut wie möglich erschlossen. Das ist der wesentliche Vorteil. Sie schreiben nur dann Typen hin, wenn sie Ihnen wirklich wichtig sind, also einen Mehrwert liefern – entweder um dem Compiler zu helfen oder als Dokumentation für den Entwickler.

Es gibt aber auch Besonderheiten im Type-System von TypeScript, die auf speziellen Eigenschaften von JavaScript und deren Benutzung beruhen. Diese Besonderheiten zeigen wir anhand von drei Beispielen: Union, Intersection und Tuple Types.

Sehen Sie auch: Fragen und Antworten zu Java 8: Q&A

Union Types

Wir fangen mit Union Types an. Denken wir einmal über eine Funktion nach, die entweder einen String oder eine Zahl als Parameter bekommt und dann abhängig vom Typ entweder die Länge des Strings oder das Ergebnis einer arithmetische Operation auf der Zahl zurückgibt.

Hier die Funktion mit TypeScript-Typeninformationen:

function machWas(x: string | number) {
  if (typeof x === 'string') { // A
    return x.length; // B
  } else {
    return x - 1; // C
  }
}

Der Typ steht bei TypeScript hinter dem Parameter, damit ist der Typ von x string | number. Das ist ein sogenannter Union-Type, der besagt, dass x entweder vom Typ string oder number ist. Das wäre beispielsweise in Java schon gar nicht mehr so leicht gewesen. Man hätte Objekt übergeben können, aber dann hätten Sie einen Down-Cast machen müssen und damit wäre die Typsicherheit nicht mehr durch den Compiler gecheckt gewesen.

Bei TypeScript ist das anders. Die Funktion oben geht problemlos durch den TypeScript Compiler, aber nur, weil alles zusammen passt. Durch den Check in Zeile A ist für den TypeScript Compiler klar, dass x in Zeile B zwingend ein String sein muss.

Strings haben eine length-Property, alles klar. Hätten wir dort aber return x * 10; geschrieben, hätte das einen Fehler gegeben, da arithmetische Operationen auf Strings nicht definiert sind. Es wird noch besser: Da x ja entweder string oder number sein muss, aber im else-Branch in Zeile C kein string sein kann, wird der Typ number inferiert. So sind in Zeile C nur Operationen erlaubt, die auf number definiert sind.

Was ist nun aber der Rückgabetyp von machWas? Gucken wir uns dazu den Aufruf an:

const res1: number = machWas(10);
console.log(res1);
// Ausgabe: 9
const res2: number = machWas('Olli');
console.log(res2);
// Ausgabe: 4

Zunächst sehen wir, dass je nach Typ, der an machWas übergeben wird, das “fachlich” richtige Ergebnis zurückkommt. Außerdem sehen wir, dass die Variablen res1 und res2 hier als number deklariert sind, obwohl an machWas selber kein Rückgabetyp deklariert ist. Das ist aber auch nicht notwendig: Der Compiler kann schon statisch, also nicht erst zur Laufzeit, feststellen, dass auf jeden Fall eine number zurückkommt. Deswegen müssen wir dies nicht an der Methodendeklaration selber hinschreiben. Übrigens könnten wir auch hier die Typinformation von res1 und res2 weglassen, denn TypeScript würde auch da erkennen, dass es sich um Variablen vom Typ number handeln muss.

Intersection Types

Neben den Union Types gibt es auch Intersection Types. Damit können Sie ausdrücken, dass ein Parameter nicht nur genau ein Interface oder genau eine Klasse erfüllen muss, sondern mehrere. Und das, ohne erst einen neuen expliziten Untertyp erstellen zu müssen. Für das folgende Beispiel müssen Sie wissen, dass man in TypeScript in Interfaces neben Methoden auch Felder definieren kann. In der folgenden Funktion machWasAnderes wird ein Objekt erwartet, das die beiden Interfaces HasAge und HasName implementiert:

interface HasAge {
  age: number;
}

interface HasName {
  name: string;
}

function machWasAnderes(x: HasAge & HasName) {
  return `${x.name} ist ${x.age}`;
}

const res: string = machWasAnderes({name: 'Olli', age: 45});
console.log(res);
// Olli ist 45

Tuple Types

In JavaScript kann jedes Element eines Arrays einen anderen Typ bekommen. Neben Objektliteralen ist dies eine Art, um aus einer Funktion mehr als einen Rückgabewert zu liefern. Mit TypeScript können Sie festlegen, wie das Array aussieht, das eine Funktion zurückliefert. Um das zu zeigen, bauen wir die Funktion von oben noch ein wenig um, so dass sie neben dem formatierten String auch noch den extrahierten Namen und das Alter zurückgibt:

function machWasAnderes(x: HasAge & HasName): [string, string, number] {
  return [`${x.name} is ${x.age}`, x.name, x.age];
}

Den Rückgabetyp geben wir hinter der Parameterdeklaration an. In diesem Fall handelt es sich dabei um ein Array mit genau 3 Elementen mit den Typen string, string und number. So etwas nennt man auch Tuple. Der Rückgabe-Wert ist nun pro Element getypt und wird auch vom Compiler gecheckt:

const res = machWasAnderes({name: 'Olli', age: 45});
const str: string = res[1];
const num: number = res[2];
// Error: string not assingable to number
// const num2: number = res[1];

Ausblick

Es gibt noch eine ganze Menge weiterer Eigenschaften, die TypeScript sowohl mächtig, als auch einfach zu verstehen machen.

So ist es sogar möglich, bestehenden JavaScript-Bibliotheken durch externe Deklarationen nachträglich Typinformationen hinzuzufügen. In diesem Zusammenhang sei auf das Projekt DefinitelyTyped verwiesen, das eine sehr große Menge solcher Deklarationen für alle gängigen JavaScript-Bibliotheken fertig zur Verfügung stellt.

Durch die Typisierung kann der Compiler dann auch Fehler in der Benutzung externer Bibliotheken bereits vor dem Ablauf der Anwendung diagnostizieren.

Auch Analyse, Code-Completion und Refactoring wird durch TypeScript mit entsprechenden IDEs möglich. Ein gutes Beispiel hierfür ist die Open-Source IDE Visual Studio Code von Microsoft, die all diese Features anbietet und nicht nur für Windows, sondern auch für Linux und MacOS verfügbar ist.

Wenn Sie TypeScript sofort ohne IDE ausprobieren möchten, können Sie das übrigens online tun. Unter der Adresse http://www.typescriptlang.org/Playground gibt es eine “Spielwiese”, auf der Sie direkt eigene oder auch vorgefertigte Code-Beispiele ausprobieren können.

Und da sich JavaScript und TypeScript problemlos parallel in einem Projekt verwenden lassen, kann man TypeScript ganz einfach auch gefahrlos in einem echten Projekt Schritt-für-Schritt einführen und testen, ohne gleich die ganze Anwendung darauf umstellen zu müssen.

International JavaScript Conference
Hans-Christian Otto

Testing React Applications

by Hans-Christian Otto (Suora GmbH)

Sebastian Witalec

Building a Robo-Army with Angular

by Sebastian Witalec (Progress)

API Summit 2018
Christian Schwendtner

GraphQL – A query language for your API

mit Christian Schwendtner (PROGRAMMIERFABRIK)

Geschrieben von
Nils Hartmann
Nils Hartmann
Nils Hartmann ist Softwareentwickler und Softwarearchitekt. Er hat langjährige Erfahrung in der Entwicklung von großen Java-Enterprise-Anwendungen und beschäftigt sich mit dem server- und clientseitigen Einsatz von JavaScript. Nils ist unter www.nilshartmann.net zu erreichen. Twitter: @nilshartmann
Oliver Zeigermann
Oliver Zeigermann
Oliver Zeigermann ist Softwareentwicklungs-Enthusiast, der sich besonders für Singe-Pages-Webanwendungen (SPAs) in Java und JavaScript interessiert. Er lebt in Hamburg und arbeitet als selbständiger Consultant, Trainer, Coach und Software-Entwickler. Twitter: @djcordhose
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: