Klassen Grundlagen
Lerne die Grundlagen von Klassen in TypeScript - Properties, Konstruktoren und Methoden.
Aktualisiert:
Klassen Grundlagen
TypeScript erweitert JavaScript-Klassen um Typisierung und zusätzliche Features. In diesem Kapitel lernst du die Grundlagen von Klassen in TypeScript.
Klassen definieren
class User {
// Properties mit Typen
name: string;
age: number;
email: string;
// Konstruktor
constructor(name: string, age: number, email: string) {
this.name = name;
this.age = age;
this.email = email;
}
// Methode
greet(): string {
return `Hallo, ich bin ${this.name}!`;
}
}
const user = new User("Max", 25, "max@example.com");
console.log(user.greet()); // "Hallo, ich bin Max!"
Parameter Properties
Kurzschreibweise für Constructor-Properties:
class User {
// Properties werden automatisch erstellt und zugewiesen
constructor(
public name: string,
public age: number,
public email: string
) {}
greet(): string {
return `Hallo, ich bin ${this.name}!`;
}
}
// Gleiches Ergebnis wie vorher
const user = new User("Max", 25, "max@example.com");
Readonly Properties
Properties, die nur einmal gesetzt werden können:
class Config {
constructor(
public readonly apiUrl: string,
public readonly timeout: number
) {}
}
const config = new Config("https://api.example.com", 5000);
// config.apiUrl = "other"; // Fehler: Cannot assign to 'apiUrl'
Optionale Properties
class User {
constructor(
public name: string,
public email: string,
public age?: number, // Optional
public bio: string = "No bio" // Mit Default
) {}
}
const user1 = new User("Max", "max@example.com");
const user2 = new User("Anna", "anna@example.com", 30, "Developer");
Methoden
class Calculator {
private result: number = 0;
add(n: number): this {
this.result += n;
return this;
}
subtract(n: number): this {
this.result -= n;
return this;
}
multiply(n: number): this {
this.result *= n;
return this;
}
getResult(): number {
return this.result;
}
reset(): this {
this.result = 0;
return this;
}
}
// Method Chaining
const result = new Calculator()
.add(10)
.multiply(2)
.subtract(5)
.getResult();
console.log(result); // 15
Getter und Setter
class Circle {
constructor(private _radius: number) {}
// Getter
get radius(): number {
return this._radius;
}
// Setter mit Validierung
set radius(value: number) {
if (value <= 0) {
throw new Error("Radius muss positiv sein");
}
this._radius = value;
}
// Computed Property
get area(): number {
return Math.PI * this._radius ** 2;
}
get circumference(): number {
return 2 * Math.PI * this._radius;
}
}
const circle = new Circle(5);
console.log(circle.area); // 78.54...
console.log(circle.circumference); // 31.42...
circle.radius = 10;
console.log(circle.area); // 314.16...
Statische Members
Properties und Methoden auf der Klasse selbst:
class MathUtils {
static readonly PI = 3.14159;
static square(n: number): number {
return n * n;
}
static cube(n: number): number {
return n * n * n;
}
static factorial(n: number): number {
if (n <= 1) return 1;
return n * MathUtils.factorial(n - 1);
}
}
// Zugriff ohne Instanz
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.square(5)); // 25
console.log(MathUtils.factorial(5)); // 120
Statische Factory Methods
class User {
private constructor(
public id: number,
public name: string,
public email: string
) {}
// Factory Methods
static create(name: string, email: string): User {
const id = Math.floor(Math.random() * 10000);
return new User(id, name, email);
}
static fromJSON(json: string): User {
const data = JSON.parse(json);
return new User(data.id, data.name, data.email);
}
}
const user1 = User.create("Max", "max@example.com");
const user2 = User.fromJSON('{"id": 1, "name": "Anna", "email": "anna@example.com"}');
Index Signatures in Klassen
class Dictionary {
[key: string]: string | ((key: string) => string | undefined);
get(key: string): string | undefined {
return this[key] as string | undefined;
}
set(key: string, value: string): void {
this[key] = value;
}
}
const dict = new Dictionary();
dict.set("hello", "Hallo");
dict.set("goodbye", "Auf Wiedersehen");
console.log(dict.get("hello")); // "Hallo"
console.log(dict["goodbye"]); // "Auf Wiedersehen"
Klassen und Interfaces
interface Printable {
print(): void;
}
interface Serializable {
toJSON(): string;
}
class Document implements Printable, Serializable {
constructor(
public title: string,
public content: string
) {}
print(): void {
console.log(`=== ${this.title} ===`);
console.log(this.content);
}
toJSON(): string {
return JSON.stringify({
title: this.title,
content: this.content
});
}
}
const doc = new Document("Readme", "Hello World");
doc.print();
console.log(doc.toJSON());
Praktische Beispiele
Event Emitter
type EventHandler<T> = (data: T) => void;
class EventEmitter<Events extends Record<string, unknown>> {
private handlers = new Map<keyof Events, Function[]>();
on<K extends keyof Events>(
event: K,
handler: EventHandler<Events[K]>
): void {
const existing = this.handlers.get(event) || [];
this.handlers.set(event, [...existing, handler]);
}
off<K extends keyof Events>(
event: K,
handler: EventHandler<Events[K]>
): void {
const existing = this.handlers.get(event) || [];
this.handlers.set(event, existing.filter(h => h !== handler));
}
emit<K extends keyof Events>(event: K, data: Events[K]): void {
const handlers = this.handlers.get(event) || [];
handlers.forEach(handler => handler(data));
}
}
// Verwendung
type AppEvents = {
login: { userId: number };
logout: { userId: number };
error: { message: string };
};
const events = new EventEmitter<AppEvents>();
events.on("login", (data) => {
console.log(`User ${data.userId} logged in`);
});
events.emit("login", { userId: 1 });
Repository Pattern
class Repository<T extends { id: number }> {
private items: T[] = [];
findAll(): T[] {
return [...this.items];
}
findById(id: number): T | undefined {
return this.items.find(item => item.id === id);
}
create(item: T): T {
this.items.push(item);
return item;
}
update(id: number, updates: Partial<T>): T | undefined {
const item = this.findById(id);
if (item) {
Object.assign(item, updates);
}
return item;
}
delete(id: number): boolean {
const index = this.items.findIndex(item => item.id === id);
if (index !== -1) {
this.items.splice(index, 1);
return true;
}
return false;
}
}
interface User {
id: number;
name: string;
email: string;
}
const userRepo = new Repository<User>();
userRepo.create({ id: 1, name: "Max", email: "max@example.com" });
userRepo.create({ id: 2, name: "Anna", email: "anna@example.com" });
console.log(userRepo.findAll());
console.log(userRepo.findById(1));
Zusammenfassung
- Properties müssen deklariert werden
- Parameter Properties für kürzeren Code
- readonly für unveränderliche Properties
- Getter/Setter für berechnete Properties
- static für Klassen-Level Members
- implements für Interface-Contracts
Im nächsten Kapitel lernst du Access Modifiers!