Praxis
TypeScript Klassen: Objektorientierte Programmierung mit Typen
Lerne, wie Klassen in TypeScript funktionieren, wie du Zugriffsmodifikatoren, Vererbung und Interfaces kombinierst und welche TypeScript-spezifischen Features existieren.
Inhalt
TypeScript Klassen: Objektorientierte Programmierung mit Typen
TypeScript erweitert JavaScript-Klassen um ein starkes Typsystem mit Zugriffsmodifikatoren, abstrakten Klassen und praezisen Typannotationen. Das Ergebnis ist objektorientierter Code, der sicherer und dokumentierter ist als reines JavaScript.
Grundstruktur einer Klasse
Eine TypeScript-Klasse sieht zunaechst wie eine JavaScript-Klasse aus, bekommt aber Typannotationen fuer Felder und Methoden:
class Fahrzeug {
marke: string;
geschwindigkeit: number;
constructor(marke: string) {
this.marke = marke;
this.geschwindigkeit = 0;
}
beschleunigen(wert: number): void {
this.geschwindigkeit += wert;
}
getGeschwindigkeit(): number {
return this.geschwindigkeit;
}
}
const auto = new Fahrzeug("BMW");
auto.beschleunigen(50);
console.log(auto.getGeschwindigkeit()); // 50
Zugriffsmodifikatoren: public, private, protected
TypeScript bietet drei Zugriffsmodifikatoren, um die Sichtbarkeit von Feldern und Methoden zu steuern:
class Bankkonto {
public inhaber: string;
private kontostand: number;
protected bankCode: string;
constructor(inhaber: string, startBetrag: number) {
this.inhaber = inhaber;
this.kontostand = startBetrag;
this.bankCode = "IBAN-DE";
}
public einzahlen(betrag: number): void {
this.kontostand += betrag;
}
public getSaldo(): number {
return this.kontostand;
}
}
const konto = new Bankkonto("Maria", 1000);
konto.einzahlen(500);
console.log(konto.getSaldo()); // 1500
// konto.kontostand; // Fehler: 'kontostand' ist privat
public ist der Standard und muss nicht explizit angegeben werden. private verhindert den Zugriff von aussen und aus Unterklassen. protected erlaubt den Zugriff in Unterklassen, aber nicht von aussen.
Kurzschreibweise fuer Konstruktorparameter
TypeScript erlaubt eine elegante Kurzschreibweise, bei der Zugriffsmodifikatoren im Konstruktor direkt die Felder deklarieren:
class Produkt {
constructor(
public readonly id: number,
public bezeichnung: string,
private preis: number,
) {}
getPreis(): number {
return this.preis;
}
}
const artikel = new Produkt(1, "TypeScript Buch", 29.99);
console.log(artikel.bezeichnung); // "TypeScript Buch"
// artikel.id = 2; // Fehler: 'id' ist readonly
Diese Schreibweise spart Boilerplate und ist in der Praxis sehr haeufig anzutreffen.
readonly-Felder
Felder mit readonly koennen nur im Konstruktor gesetzt werden:
class Konfiguration {
readonly datenbankUrl: string;
readonly port: number;
constructor(url: string, port: number) {
this.datenbankUrl = url;
this.port = port;
}
}
const config = new Konfiguration("localhost", 5432);
// config.port = 3000; // Fehler: 'port' ist readonly
Vererbung mit extends
Klassen koennen von anderen Klassen erben. Die Unterklasse erbt alle oeffentlichen und geschuetzten Mitglieder:
class Tier {
constructor(protected name: string) {}
sprechen(): string {
return this.name + " macht ein Geraeusch";
}
}
class Hund extends Tier {
constructor(name: string) {
super(name);
}
sprechen(): string {
return this.name + " bellt";
}
apportieren(): void {
console.log(this.name + " holt den Ball");
}
}
const rex = new Hund("Rex");
console.log(rex.sprechen()); // "Rex bellt"
rex.apportieren();
Der Aufruf von super() im Konstruktor ist Pflicht, wenn eine Elternklasse einen Konstruktor mit Parametern hat.
Interfaces implementieren
Klassen koennen eines oder mehrere Interfaces implementieren. Das Interface definiert den Vertrag, die Klasse die Implementierung:
interface Serialisierbar {
toJSON(): string;
fromJSON(json: string): void;
}
interface Validierbar {
validieren(): boolean;
}
class Formular implements Serialisierbar, Validierbar {
private felder: Record<string, string> = {};
toJSON(): string {
return JSON.stringify(this.felder);
}
fromJSON(json: string): void {
this.felder = JSON.parse(json) as Record<string, string>;
}
validieren(): boolean {
return Object.keys(this.felder).length > 0;
}
}
Abstrakte Klassen
Abstrakte Klassen koennen nicht direkt instanziiert werden und erzwingen, dass Unterklassen bestimmte Methoden implementieren:
abstract class Form {
abstract berechneFlaeche(): number;
abstract berechneUmfang(): number;
beschreibe(): string {
return "Flaeche: " + this.berechneFlaeche() + ", Umfang: " + this.berechneUmfang();
}
}
class Kreis extends Form {
constructor(private radius: number) {
super();
}
berechneFlaeche(): number {
return Math.PI * this.radius * this.radius;
}
berechneUmfang(): number {
return 2 * Math.PI * this.radius;
}
}
class Rechteck extends Form {
constructor(private breite: number, private hoehe: number) {
super();
}
berechneFlaeche(): number {
return this.breite * this.hoehe;
}
berechneUmfang(): number {
return 2 * (this.breite + this.hoehe);
}
}
const formen: Form[] = [new Kreis(5), new Rechteck(4, 6)];
formen.forEach((f) => console.log(f.beschreibe()));
Statische Mitglieder
Statische Felder und Methoden gehoeren zur Klasse selbst, nicht zur Instanz:
class MathHilfsmittel {
static readonly PI = 3.14159;
static kreisFalche(radius: number): number {
return MathHilfsmittel.PI * radius * radius;
}
}
console.log(MathHilfsmittel.PI);
console.log(MathHilfsmittel.kreisFalche(3));
Getter und Setter
TypeScript unterstuetzt JavaScript-Getter und Setter, die wie Eigenschaften aussehen, aber Logik enthalten koennen:
class Temperatur {
private _celsius: number;
constructor(celsius: number) {
this._celsius = celsius;
}
get celsius(): number {
return this._celsius;
}
set celsius(wert: number) {
if (wert < -273.15) {
throw new Error("Unter dem absoluten Nullpunkt");
}
this._celsius = wert;
}
get fahrenheit(): number {
return (this._celsius * 9) / 5 + 32;
}
}
const temp = new Temperatur(25);
console.log(temp.fahrenheit); // 77
temp.celsius = 100;
TypeScript-Klassen im Playground testen
Das Playground eignet sich gut zum Experimentieren mit Klassen-Features. Besonders aufschlussreich ist es, den generierten JavaScript-Code zu betrachten: TypeScript-Zugriffsmodifikatoren verschwinden zur Laufzeit, readonly wird zu einer normalen Eigenschaft und abstrakte Klassen werden zu regulaeren Klassen ohne Schutz gegen direkte Instanziierung.
Fazit
TypeScript-Klassen kombinieren das vertraute JavaScript-Klassen-Modell mit einem praezisen Typsystem. Zugriffsmodifikatoren, readonly, abstrakte Klassen und Interface-Implementierungen machen OOP-Code in TypeScript sicherer und selbstdokumentierender als in reinem JavaScript.
Häufige Fragen
Was ist der Unterschied zwischen 'private' in TypeScript und dem '#' in JavaScript?
Das TypeScript-Schluesselwort 'private' wird nur zur Kompilierzeit geprueft und ist zur Laufzeit weiterhin zugreifbar. Das ECMAScript-native '#' macht ein Feld wirklich privat zur Laufzeit. Fuer echte Kapselung in JavaScript-Laufzeitumgebungen sollte man '#' verwenden.
Kann eine TypeScript-Klasse mehrere Interfaces implementieren?
Ja, eine Klasse kann beliebig viele Interfaces implementieren, indem sie mit Komma getrennt nach 'implements' aufgelistet werden. Die Klasse muss dann alle Methoden und Felder jedes Interfaces bereitstellen.
Was sind abstrakte Klassen?
Abstrakte Klassen koennen nicht direkt instanziiert werden und dienen als Blaupause fuer abgeleitete Klassen. Sie koennen abstrakte Methoden definieren, die von jeder konkreten Unterklasse implementiert werden muessen.
Quellen
Über die Autorenschaft
Jan-Tristan Rudat
Redakteur typescript-playground.de
Themengebiet: Generationen, Kulturgeschichte, Sternzeichen, Pop-Phänomene rund ums Alter
Mehr über Jan-Tristan Rudat →Verwandte Artikel
Grundlagen
Was ist TypeScript? Eine Einführung in die typisierte JavaScript-Erweiterung
TypeScript erweitert JavaScript um statische Typen und macht große Codebases wartbarer. Lerne die Grundlagen, die Geschichte und die wichtigsten Vorteile von TypeScript.
Lesezeit 7 Min.
Grundlagen
TypeScript vs. JavaScript: Die wichtigsten Unterschiede im Überblick
TypeScript und JavaScript unterscheiden sich grundlegend in der Typprüfung, Werkzeugunterstützung und Wartbarkeit. Dieser Ratgeber erklärt die Unterschiede und hilft bei der Wahl der richtigen Sprache.
Lesezeit 8 Min.
Typen
TypeScript Typen Grundlagen: string, number, boolean und mehr
Die primitiven Typen string, number und boolean sind das Fundament von TypeScript. Dieser Ratgeber erklärt alle grundlegenden Typen mit praktischen Beispielen.
Lesezeit 9 Min.