TypeScript, als Superset von JavaScript, bietet alle objektorientierten Features von JavaScript und erweitert diese um einige zusätzliche Funktionen. Diese zusätzlichen Funktionen sind stark von klassenbasierten objektorientierten Sprachen wie Java und C# inspiriert und sollen die Entwicklung großer und komplexer Anwendungen erleichtern.
Klassen in TypeScript ähneln Klassen in anderen objektorientierten Sprachen wie Java oder C#. Sie ermöglichen die Erstellung von komplexen benutzerdefinierten Typen mit Eigenschaften (auch als Felder oder Instanzvariablen bezeichnet) und Methoden.
Ein Beispiel für eine Klasse in TypeScript könnte so aussehen:
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound(): void {
console.log(this.name + ' makes a sound.');
}
}
let dog = new Animal('Dog');
dog.makeSound(); // Ausgabe: "Dog makes a sound."Hier definieren wir eine Klasse Animal mit einer
Eigenschaft name und einer Methode
makeSound.
Klassen in TypeScript unterstützen auch Konzepte wie Vererbung und Polymorphie:
class Dog extends Animal {
makeSound(): void {
console.log(this.name + ' barks.');
}
}
let dog = new Dog('Dog');
dog.makeSound(); // Ausgabe: "Dog barks."In diesem Beispiel erweitert die Dog-Klasse die
Animal-Klasse und überschreibt die
makeSound-Methode.
Insgesamt sind sowohl Interfaces als auch Klassen wichtige Konzepte in TypeScript, die dazu beitragen, den Code strukturierter, sicherer und wiederverwendbarer zu gestalten.
Vererbung ist ein grundlegendes Konzept der objektorientierten Programmierung und es ist auch in TypeScript vorhanden. Durch die Vererbung können Klassen Eigenschaften und Methoden von anderen Klassen erben und dabei den Code wiederverwenden und besser strukturieren.
In TypeScript wird die Vererbung mit den Schlüsselwörtern
extends und super umgesetzt.
Hier ist ein einfaches Beispiel für die Vererbung in TypeScript:
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
move(distance: number) {
console.log(`${this.name} moved ${distance} meters.`);
}
}
class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}
const dog = new Dog('Max');
dog.bark(); // "Woof! Woof!"
dog.move(10); // "Max moved 10 meters."In diesem Beispiel erstellen wir zunächst eine Basisklasse
Animal mit Eigenschaften und Methoden, die alle Tiere
gemeinsam haben könnten, wie z.B. einen Namen und eine
move-Methode. Dann erstellen wir eine
Dog-Klasse, die die Animal-Klasse erweitert.
Das bedeutet, dass die Dog-Klasse alle Eigenschaften und
Methoden der Animal-Klasse erbt und zusätzliche
Eigenschaften und Methoden hinzufügen kann, die spezifisch für Hunde
sind.
Das Schlüsselwort super wird verwendet, um auf den
Konstruktor der Basisklasse zuzugreifen:
class Cat extends Animal {
constructor(name: string) {
super(name); // ruft den Konstruktor der Animal-Klasse auf
}
meow() {
console.log('Meow!');
}
}
const cat = new Cat('Felix');
cat.meow(); // "Meow!"
cat.move(5); // "Felix moved 5 meters."In diesem Beispiel erstellen wir eine Cat-Klasse, die
ebenfalls die Animal-Klasse erweitert. Im Konstruktor der
Cat-Klasse verwenden wir super, um den
Konstruktor der Animal-Klasse aufzurufen und den Namen des
Tieres zu setzen.
Die Vererbung in TypeScript ermöglicht es, hierarchische Strukturen zu erstellen und den Code zu organisieren, indem gemeinsame Eigenschaften und Verhaltensweisen in Basisklassen kapsuliert und spezifische Eigenschaften und Verhaltensweisen in abgeleiteten Klassen hinzugefügt werden.
Interfaces in TypeScript ermöglichen es, benutzerdefinierte Typen zu definieren. Sie können als Verträge für Klassen dienen, die definieren, welche Eigenschaften und Methoden eine Klasse implementieren muss:
interface Drivable {
drive(): void;
}
class Car implements Drivable {
drive() {
console.log('Driving a car.');
}
}Konstruktoren sind spezielle Methoden in einer Klasse, die aufgerufen
werden, um ein neues Objekt der Klasse zu erstellen und zu
initialisieren. In TypeScript, ähnlich wie in anderen objektorientierten
Sprachen, definiert man Konstruktoren mit dem Schlüsselwort
constructor.
Hier ist ein einfaches Beispiel für einen Konstruktor in TypeScript:
class Car {
color: string;
constructor(color: string) {
this.color = color;
}
}
let myCar = new Car('red');In diesem Beispiel definiert die Car-Klasse einen
Konstruktor, der einen Parameter color nimmt. Innerhalb des
Konstruktors wird der Wert des color-Parameters auf die
color-Eigenschaft des neu erstellten
Car-Objekts gesetzt. Wenn ein neues Car-Objekt
mit new Car('red') erstellt wird, wird der Konstruktor
aufgerufen und das Car-Objekt wird mit der Farbe
'red' initialisiert.
In TypeScript ist es auch möglich, mehrere Konstruktorparameter zu definieren:
class Car {
color: string;
year: number;
constructor(color: string, year: number) {
this.color = color;
this.year = year;
}
}
let myCar = new Car('red', 2022);In diesem Beispiel nimmt der Konstruktor der Car-Klasse
zwei Parameter, color und year, und
initialisiert die entsprechenden Eigenschaften des
Car-Objekts.
Darüber hinaus bietet TypeScript eine verkürzte Syntax, um Konstruktoren zu definieren und gleichzeitig Klasseneigenschaften zu deklarieren:
class Car {
constructor(public color: string, public year: number) {}
}
let myCar = new Car('red', 2022);In diesem Beispiel werden color und year
sowohl als Konstruktorparameter als auch als öffentliche Eigenschaften
der Klasse definiert. Diese Syntax kann den Code verkürzen und
übersichtlicher machen, insbesondere wenn eine Klasse viele
Eigenschaften hat.
In TypeScript können Sie Zugriffsmodifikatoren verwenden, um zu
bestimmen, welche Teile einer Klasse von außen zugänglich sind. Es gibt
drei Zugriffsmodifikatoren: public, private
und protected.
Wenn ein Mitglied (d.h., eine Eigenschaft oder Methode) einer Klasse
als public deklariert wird, kann es von überall aus
zugänglich gemacht werden. Mitglieder sind standardmäßig
public, wenn kein Zugriffsmodifikator angegeben wird.
class Car {
public color: string;
constructor(color: string) {
this.color = color;
}
}
let myCar = new Car('red');
console.log(myCar.color); // Ausgabe: "red"Wenn ein Mitglied als private deklariert wird, kann es
nur innerhalb der Klasse, in der es definiert ist, zugegriffen
werden.
class Car {
private color: string;
constructor(color: string) {
this.color = color;
}
displayColor() {
console.log('The color of the car is ' + this.color);
}
}
let myCar = new Car('red');
// Ausgabe: "The color of the car is red"
myCar.displayColor();
// Fehler: Property 'color' is private and only accessible
// within class 'Car'.
console.log(myCar.color); Ein protected Mitglied ist ähnlich wie ein
private Mitglied, kann aber auch in abgeleiteten Klassen
zugegriffen werden.
class Car {
protected color: string;
constructor(color: string) {
this.color = color;
}
}
class SportsCar extends Car {
displayColor() {
console.log('The color of the sports car is ' + this.color);
}
}
let mySportsCar = new SportsCar('red');
// Ausgabe: "The color of the sports car is red"
mySportsCar.displayColor(); In diesem Beispiel kann die abgeleitete Klasse SportsCar
auf das protected-Mitglied color der
Basisklasse Car zugreifen.
Diese Zugriffsmodifikatoren helfen dabei, die Prinzipien der Datenkapselung und der Vererbung, die zentrale Konzepte der objektorientierten Programmierung, zu implementieren. Sie ermöglichen es Ihnen, die Interaktion mit den Mitgliedern einer Klasse zu steuern und zu gewährleisten, dass diese nur auf sichere und kontrollierte Weise verwendet werden.
Getter und Setter sind spezielle Methoden in einer Klasse, die zum Abrufen (Get) und Ändern (Set) der Werte von privaten Klasseneigenschaften verwendet werden. Sie sind ein Teil des Konzepts der Datenkapselung in der objektorientierten Programmierung.
In TypeScript können Sie Getter und Setter mit den Schlüsselwörtern
get und set definieren.
Hier ist ein einfaches Beispiel:
class Car {
private _color: string;
constructor(color: string) {
this._color = color;
}
// Getter
get color(): string {
return this._color;
}
// Setter
set color(newColor: string) {
if (!newColor) {
throw new Error('Please provide a valid color.');
}
this._color = newColor;
}
}
let myCar = new Car('red');
console.log(myCar.color); // Ausgabe: "red"
myCar.color = 'blue';
console.log(myCar.color); // Ausgabe: "blue"
myCar.color = ''; // Fehler: Please provide a valid color.In diesem Beispiel hat die Car-Klasse eine private
Eigenschaft _color und einen Getter und einen Setter für
diese Eigenschaft. Der Getter color gibt den Wert von
_color zurück, und der Setter color ändert den
Wert von _color, aber nur wenn der neue Wert ein gültiger
String ist.
Getter und Setter können verwendet werden, um die Datenintegrität zu gewährleisten, indem sie sicherstellen, dass ungültige Werte nicht gesetzt werden können. Sie können auch verwendet werden, um zusätzliche Logik auszuführen, wenn eine Eigenschaft abgerufen oder geändert wird, wie z.B. das Loggen von Änderungen oder das Auslösen von Ereignissen.
Abstrakte Klassen sind in TypeScript eine fortgeschrittene Funktion der objektorientierten Programmierung. Sie dienen als Basis für andere Klassen und können nicht direkt instanziiert werden. Eine abstrakte Klasse kann sowohl konkrete Methoden und Eigenschaften (die Implementierungen enthalten) als auch abstrakte Methoden und Eigenschaften (die keine Implementierungen enthalten) enthalten.
Abstrakte Methoden und Eigenschaften müssen in jeder konkreten
(nicht-abstrakten) Klasse, die von der abstrakten Klasse erbt,
implementiert werden. Abstrakte Klassen werden mit dem Schlüsselwort
abstract definiert.
Hier ist ein einfaches Beispiel für eine abstrakte Klasse in TypeScript:
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log('Moving along...');
}
}
class Dog extends Animal {
makeSound() {
console.log('Woof! Woof!');
}
}
const myDog = new Dog();
myDog.makeSound(); // Ausgabe: "Woof! Woof!"
myDog.move(); // Ausgabe: "Moving along..."In diesem Beispiel ist Animal eine abstrakte Klasse mit
einer abstrakten Methode makeSound und einer konkreten
Methode move. Die Dog-Klasse erbt von der
Animal-Klasse und implementiert die abstrakte Methode
makeSound.
Versuchen wir, ein Objekt der abstrakten Klasse Animal
direkt zu instanziieren, erhalten wir einen Kompilierungsfehler:
// Fehler: Cannot create an instance of an abstract class.
const myAnimal = new Animal(); Abstrakte Klassen sind besonders nützlich, wenn Sie eine gemeinsame Struktur und/oder Funktionalität für eine Gruppe von verwandten Klassen definieren möchten, aber sicherstellen möchten, dass bestimmte Methoden oder Eigenschaften in jeder spezifischen Klasse eindeutig implementiert werden.