© paseven/Shutterstock.com
Teil 3: TypeScript - Interfaces, Klassen und Generics

Objektorientierte Programmierung


TypeScript bietet alle Konstrukte, um objektorientiert zu programmieren. Mit Interfaces und Klassen lässt sich robuster Code schreiben. Dabei bietet TypeScript insbesondere beim Erstellen von Klassen einige interessante Konzepte, die es so in der C#-Welt bisher nicht gibt, wie beispielsweise Parameter Properties. Parameter Properties sind eine Kurzform zum Erstellen einer Property, die direkt mit einem Konstruktorparameter initialisiert wird. Neben den Grundlagen zu Interfaces und Klassen geht dieser Artikel auch auf Generics ein und zeigt zudem, was bezüglich Typen in TypeScript anders ist als in C#.

TypeScript bietet mit Interfaces [1] ein Konstrukt an, das C#-Entwicklern bekannt ist. Ein Interface stellt eine Art Vertrag dar. Es wird genutzt, um klare Abgrenzungen im Code zu erstellen. Wird das Interface nicht eingehalten, führt dies in TypeScript – wie auch in C# – zu einem Compile-Fehler. Wie so oft in der Welt der Softwareentwicklung sagt nicht ein Bild, sondern ein Beispiel mehr als tausend Worte: Listing 1 zeigt die getFullName-Funktion. Sie besitzt einen friend-Parameter. Intern wird der Wert der firstName Property in der fullName-Variablen gespeichert. Ist auf dem friend-Objekt auch eine lastName Property vorhanden, wird dieser Wert dem Wert der fullName-Variablen angehängt. Anschließend wird der Wert der fullName-Variablen aus der Funktion zurückgegeben.

Der JavaScript-Code aus Listing 1 hat den Nachteil, dass an die Methode ein x-beliebiges Objekt übergeben werden kann, da der friend-Parameter keinen Typ hat. Zudem ist ohne Blick auf den Methodenkörper nicht klar, dass der friend-Parameter eine firstName Property und eine optionale lastName Property haben sollte. Es braucht in JavaScript folglich Kommentare zur Dokumentation. In TypeScript kann ein Interface das Problem lösen. Dabei werden optionale Properties mit einem Fragezeichen nach dem Property-Namen deklariert. Listing 2 zeigt das Friend-Interface, dessen lastName Property optional ist. Das Interface lässt sich auf dem Parameter der getFullName-Funktion als Typ angeben. Wird ein Objekt ohne firstName Property an die getFullName-Methode übergeben, führt dies zu einem Compile-Fehler. Darüber hinaus ist der Typ auf dem Parameter sehr aufschlussreich, was an die Funktion zu übergeben ist. Einen Kommentar zur Dokumentation benötigt es nicht. Zudem bietet der Typ alle Infos für Codeeditoren wie Visual Studio Code, um beim Aufruf der Methode IntelliSense für den Parameter anzuzeigen. Das heißt, wird beim Aufruf ein Objekt mit der JSON-Syntax erstellt, zeigt Visual Studio Code IntelliSense für die beiden Properties firstName und lastName.

function getFullName(friend) {
let fullName = friend.firstName;
if(friend.lastName) {
fullName += " " + friend.lastName;
}
return fullName;
}

Listing 1

interface Friend {
firstName: string;
lastName?: string;
}
function getFullName(friend: Friend) {
...
}

Listing 2

Jetzt lässt sich die getFullName-Funktion wie folgt aufrufen:

getFullName({firstName:"Thomas",lastName:"Huber"});
getFullName({firstName:"Thomas"});
getFullName({}); // Error: firstName fehlt

Eine besondere Eigenschaft eines Interface ist, dass es keine Implementierung hat. Es ist lediglich ein Typ. Da es in JavaScript keine Typen gibt, enthält der generierte JavaScript-Code kein Interface.

Klassen einsetzen

Seit ES2015 sind Klassen Teil des JavaScript-Standards. Mit TypeScript lassen sich wie in ES2015 Klassen nutzen und zudem nach ES5 oder ES3 kompilieren [2]. Eine Klasse in TypeScript hat Properties, Methoden und einen Konstruktor, also ganz so, wie man es von einer typischen Klasse erwartet. Im Gegensatz zum Interface hat eine Klasse eine Implementierung. Somit wird im Gegensatz zum Interface für eine in TypeScript erstellte Klasse auch JavaScript-Code generiert.

Listing 3 zeigt die Friend-Klasse. Sie besitzt eine firstName Property und eine optionale lastName Property. Der Konstruktor wird mit dem Schlüsselwort constructor angegeben und enthält die zwei Parameter firstName und lastName. Der lastName-Parameter ist mit einem Fragezeichen als optionaler Parameter definiert und kann daher beim Aufruf des Konstruktors weggelassen werden kann. Im Konstruktor selbst werden die beiden Properties firstName und lastName mit den Werten der Parameter initialisiert. Zum Zugriff auf die Properties ist dabei zwingend das this-Schlüsselwort notwendig. Damit wird wie in C# die Instanz der Klasse referenziert.

class Friend {
firstName: string;
lastName?: string;

constructor(firstName: string, lastName?: string) {
this.firstName = firstName;
this.lastName = lastName;
}

getFullName(): string {
let fullName = this.firstName;
if(this.lastName) {
fullName+= " "+this.lastName;
}
return fullName;
}
}

Listing 3

Neben den Properties und dem Konstruktor enthält die Friend-Klasse aus Listing 3 noch die getFullName-Methode. Die Implementierung entspricht der getFullName-Funktion, wie sie bereits in Listing 1 gezeigt wurde. Anstelle von Parametern wird jedoch auf die Properties firstName und lastName der Friend-Instanz zugegriffen, womit auch hier das this-Schlüsselwort zum Einsatz kommt.

Um eine Instanz der Friend-Klasse aus Listing 3 zu erzeugen, wird der Konstruktor wie in C# mit dem new-Schlüsselwort aufgerufen. Listing 4 zeigt dies. Es werden zwei Friend-Objekte instanziiert, eines mit und eines ohne Nachnamen. Anschließend wird auf jedem Friend-Objekt die getFullName-Methode aufgerufen und das Ergebnis an der Konsole des Browsers ausgegeben.

let friend1 = new Friend("Thomas","Huber");
let friend2 = new Friend("Julia");
console.log(friend1.getFullName()); // Logs "Thomas Huber"
console.log(friend2.getFullName()); // Logs "Julia"

Listing 4

Beim Verwenden von Klassen in TypeScript lohnt sich auch ein Blick auf den generierten JavaScript-Code. Insbesondere, wenn dabei mit der target-Compileroption gespielt wird. Diese lässt sich in der vom TypeScript-Compiler genutzten tsconfig.json-Datei einstellen. Ist die target-Compileroption auf ES5 gestellt, führt die Friend-Klasse aus Listing 3 zu dem in Listing 5 darstellten JavaScript-Code. Klassen werden in ...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang