Interfaces definieren
Lerne wie du Interfaces in TypeScript definierst und verwendest, um Objektstrukturen zu beschreiben.
Aktualisiert:
Interfaces definieren
Interfaces sind eines der Kernkonzepte in TypeScript. Sie beschreiben die Struktur von Objekten und ermöglichen es, Verträge für deinen Code zu definieren.
Interface Grundlagen
// Interface definieren
interface User {
id: number;
name: string;
email: string;
}
// Objekt muss dem Interface entsprechen
const user: User = {
id: 1,
name: "Max",
email: "max@example.com"
};
// Fehler bei fehlenden oder falschen Properties
const invalid: User = {
id: 1,
name: "Max"
// Fehler: Property 'email' is missing
};
Optionale Properties
interface Product {
id: number;
name: string;
price: number;
description?: string; // Optional
discount?: number; // Optional
}
// Beide sind gültig
const product1: Product = {
id: 1,
name: "Laptop",
price: 999
};
const product2: Product = {
id: 2,
name: "Maus",
price: 29,
description: "Wireless Gaming Mouse",
discount: 10
};
Readonly Properties
interface Config {
readonly apiKey: string;
readonly environment: "dev" | "prod";
timeout: number;
}
const config: Config = {
apiKey: "abc123",
environment: "prod",
timeout: 5000
};
config.timeout = 10000; // OK
config.apiKey = "xyz"; // Fehler: Cannot assign to 'apiKey'
Methoden in Interfaces
interface Calculator {
// Property-Syntax
add: (a: number, b: number) => number;
// Method-Syntax (gleichwertig)
subtract(a: number, b: number): number;
}
const calc: Calculator = {
add: (a, b) => a + b,
subtract(a, b) {
return a - b;
}
};
console.log(calc.add(5, 3)); // 8
console.log(calc.subtract(5, 3)); // 2
Index Signatures
Für Objekte mit dynamischen Keys:
interface StringMap {
[key: string]: string;
}
const translations: StringMap = {
hello: "Hallo",
goodbye: "Auf Wiedersehen",
thanks: "Danke"
};
translations.welcome = "Willkommen"; // OK
// Mit zusätzlichen festen Properties
interface UserScores {
name: string; // Fest
[subject: string]: string | number; // Dynamisch (muss kompatibel sein)
}
const scores: UserScores = {
name: "Max",
math: 95,
english: 88,
science: 92
};
Callable Interfaces
Interfaces für Funktionen:
interface Formatter {
(value: number): string;
}
const currencyFormatter: Formatter = (value) => {
return `${value.toFixed(2)} €`;
};
console.log(currencyFormatter(19.99)); // "19.99 €"
// Mit Properties
interface FormatterWithOptions {
(value: number): string;
precision: number;
currency: string;
}
const formatter: FormatterWithOptions = Object.assign(
(value: number) => `${value.toFixed(formatter.precision)} ${formatter.currency}`,
{ precision: 2, currency: "€" }
);
Interfaces für Klassen
interface Printable {
print(): void;
}
interface Serializable {
toJSON(): string;
}
class Document implements Printable, Serializable {
constructor(private content: string) {}
print(): void {
console.log(this.content);
}
toJSON(): string {
return JSON.stringify({ content: this.content });
}
}
const doc = new Document("Hello World");
doc.print();
console.log(doc.toJSON());
Extending Interfaces
Interfaces können andere Interfaces erweitern:
interface Animal {
name: string;
age: number;
}
interface Pet extends Animal {
owner: string;
vaccinated: boolean;
}
interface Dog extends Pet {
breed: string;
bark(): void;
}
const myDog: Dog = {
name: "Buddy",
age: 3,
owner: "Max",
vaccinated: true,
breed: "Golden Retriever",
bark() {
console.log("Woof!");
}
};
Mehrfache Vererbung
interface Timestamped {
createdAt: Date;
updatedAt: Date;
}
interface Identifiable {
id: number;
}
interface Nameable {
name: string;
}
// Kombiniere alle drei
interface Entity extends Timestamped, Identifiable, Nameable {
// Zusätzliche Properties
active: boolean;
}
const entity: Entity = {
id: 1,
name: "Test Entity",
createdAt: new Date(),
updatedAt: new Date(),
active: true
};
Declaration Merging
Interfaces mit gleichem Namen werden zusammengeführt:
interface User {
name: string;
}
interface User {
email: string;
}
// User hat jetzt beide Properties
const user: User = {
name: "Max",
email: "max@example.com"
};
Dies ist nützlich für das Erweitern von Bibliotheks-Interfaces:
// Erweitere Window-Interface
declare global {
interface Window {
myCustomProperty: string;
}
}
window.myCustomProperty = "Hello";
Generische Interfaces
interface Repository<T> {
getAll(): T[];
getById(id: number): T | undefined;
create(item: T): T;
update(id: number, item: Partial<T>): T | undefined;
delete(id: number): boolean;
}
interface User {
id: number;
name: string;
email: string;
}
class UserRepository implements Repository<User> {
private users: User[] = [];
getAll(): User[] {
return this.users;
}
getById(id: number): User | undefined {
return this.users.find(u => u.id === id);
}
create(item: User): User {
this.users.push(item);
return item;
}
update(id: number, item: Partial<User>): User | undefined {
const user = this.getById(id);
if (user) {
Object.assign(user, item);
}
return user;
}
delete(id: number): boolean {
const index = this.users.findIndex(u => u.id === id);
if (index !== -1) {
this.users.splice(index, 1);
return true;
}
return false;
}
}
Praktische Beispiele
API Response Interface
interface ApiResponse<T> {
success: boolean;
data?: T;
error?: {
code: string;
message: string;
};
meta?: {
page: number;
totalPages: number;
totalItems: number;
};
}
interface User {
id: number;
name: string;
}
function handleResponse(response: ApiResponse<User[]>): void {
if (response.success && response.data) {
response.data.forEach(user => {
console.log(user.name);
});
} else if (response.error) {
console.error(`Error ${response.error.code}: ${response.error.message}`);
}
}
Event System
interface Event {
type: string;
timestamp: Date;
}
interface ClickEvent extends Event {
type: "click";
x: number;
y: number;
target: HTMLElement;
}
interface KeyboardEvent extends Event {
type: "keyboard";
key: string;
keyCode: number;
modifiers: {
ctrl: boolean;
alt: boolean;
shift: boolean;
};
}
interface EventHandler<T extends Event> {
(event: T): void;
}
interface EventEmitter {
on<T extends Event>(type: T["type"], handler: EventHandler<T>): void;
emit<T extends Event>(event: T): void;
}
Form Configuration
interface FormField {
name: string;
label: string;
type: "text" | "email" | "password" | "number" | "select";
required?: boolean;
placeholder?: string;
validation?: {
minLength?: number;
maxLength?: number;
pattern?: RegExp;
custom?: (value: string) => boolean;
};
}
interface SelectField extends FormField {
type: "select";
options: { value: string; label: string }[];
}
interface FormConfig {
id: string;
title: string;
fields: (FormField | SelectField)[];
onSubmit: (data: Record<string, string>) => void;
}
const loginForm: FormConfig = {
id: "login",
title: "Anmelden",
fields: [
{
name: "email",
label: "E-Mail",
type: "email",
required: true,
validation: { pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ }
},
{
name: "password",
label: "Passwort",
type: "password",
required: true,
validation: { minLength: 8 }
}
],
onSubmit: (data) => console.log("Login:", data)
};
Zusammenfassung
- Interfaces beschreiben Objektstrukturen
- Optionale Properties mit
? - Readonly Properties mit
readonly - Methoden mit Property- oder Method-Syntax
- Index Signatures für dynamische Keys
- Extending für Vererbung
- Declaration Merging für Erweiterungen
Best Practices:
- Nutze Interfaces für Objekt-Shapes
- Bevorzuge
readonlywo möglich - Erweitere bestehende Interfaces statt Duplikation
- Halte Interfaces fokussiert und klein
Im nächsten Kapitel lernst du Type Aliases!