Objekt-Typen in TypeScript
Lerne wie du Objekte in TypeScript typisierst mit Inline-Typen, Type Aliases und optionalen Eigenschaften.
Aktualisiert:
Objekt-Typen in TypeScript
Objekte sind das Herzstück von JavaScript. TypeScript bietet mehrere Möglichkeiten, Objekte zu typisieren und sicherzustellen, dass sie die richtige Struktur haben.
Inline Objekt-Typen
Die einfachste Form der Objekt-Typisierung:
// Inline-Typ direkt bei der Variable
let user: { name: string; age: number } = {
name: "Max",
age: 25
};
// TypeScript prüft die Struktur
user = { name: "Anna" }; // Fehler: 'age' fehlt
user = { name: "Anna", age: "25" }; // Fehler: 'age' muss number sein
Bei Funktionsparametern
function greet(person: { name: string; age: number }): string {
return `Hallo ${person.name}, du bist ${person.age} Jahre alt!`;
}
greet({ name: "Max", age: 25 }); // OK
greet({ name: "Max" }); // Fehler: 'age' fehlt
Type Aliases
Für wiederverwendbare Typen:
// Type Alias definieren
type User = {
name: string;
age: number;
email: string;
};
// Überall verwenden
let user1: User = { name: "Max", age: 25, email: "max@example.com" };
let user2: User = { name: "Anna", age: 30, email: "anna@example.com" };
function displayUser(user: User): void {
console.log(`${user.name} (${user.email})`);
}
Optionale Eigenschaften
Mit ? markierst du optionale Properties:
type Product = {
name: string;
price: number;
description?: string; // Optional
discount?: number; // Optional
};
// Beide sind gültig:
let product1: Product = {
name: "Laptop",
price: 999
};
let product2: Product = {
name: "Maus",
price: 29,
description: "Wireless Gaming Mouse",
discount: 10
};
Optionale Eigenschaften verwenden
function displayPrice(product: Product): string {
if (product.discount) {
const discounted = product.price * (1 - product.discount / 100);
return `${discounted.toFixed(2)}€ (${product.discount}% Rabatt)`;
}
return `${product.price}€`;
}
Readonly Eigenschaften
Eigenschaften, die nicht verändert werden können:
type Config = {
readonly apiKey: string;
readonly baseUrl: string;
timeout: number; // Kann geändert werden
};
let config: Config = {
apiKey: "abc123",
baseUrl: "https://api.example.com",
timeout: 5000
};
config.timeout = 10000; // OK
config.apiKey = "xyz"; // Fehler: Cannot assign to 'apiKey'
Readonly für das gesamte Objekt
type User = {
name: string;
age: number;
};
// Alle Eigenschaften werden readonly
let user: Readonly<User> = {
name: "Max",
age: 25
};
user.name = "Anna"; // Fehler!
Index Signatures
Für Objekte mit dynamischen Schlüsseln:
// String-Keys, Number-Values
type Scores = {
[key: string]: number;
};
let gameScores: Scores = {
player1: 100,
player2: 85,
player3: 92
};
gameScores.player4 = 78; // OK - dynamische Schlüssel
Kombiniert mit festen Eigenschaften
type Config = {
version: string; // Feste Eigenschaft
[setting: string]: string | number; // Dynamische Settings
};
let config: Config = {
version: "1.0.0",
theme: "dark",
fontSize: 14,
language: "de"
};
Nested Objects
Objekte in Objekten:
type Address = {
street: string;
city: string;
zip: string;
};
type Person = {
name: string;
age: number;
address: Address; // Nested Object
};
let person: Person = {
name: "Max",
age: 25,
address: {
street: "Hauptstraße 1",
city: "Berlin",
zip: "10115"
}
};
// Zugriff auf nested Properties
console.log(person.address.city); // "Berlin"
Extending Types
Typen erweitern mit Intersection:
type BasicUser = {
name: string;
email: string;
};
type AdminUser = BasicUser & {
role: "admin";
permissions: string[];
};
let admin: AdminUser = {
name: "Max",
email: "max@example.com",
role: "admin",
permissions: ["read", "write", "delete"]
};
Record Utility Type
Für Objekte mit bestimmten Keys:
// Alle Keys müssen vom Typ string sein, alle Values vom Typ number
type StringToNumber = Record<string, number>;
// Bestimmte Keys
type UserRoles = "admin" | "editor" | "viewer";
type RolePermissions = Record<UserRoles, string[]>;
let permissions: RolePermissions = {
admin: ["read", "write", "delete"],
editor: ["read", "write"],
viewer: ["read"]
};
Praktische Beispiele
API Response
type ApiResponse<T> = {
success: boolean;
data?: T;
error?: string;
timestamp: number;
};
type User = {
id: number;
name: string;
email: string;
};
// Verwendung
function fetchUser(id: number): ApiResponse<User> {
// Simulierte Antwort
return {
success: true,
data: { id, name: "Max", email: "max@example.com" },
timestamp: Date.now()
};
}
function handleResponse(response: ApiResponse<User>): void {
if (response.success && response.data) {
console.log(`User: ${response.data.name}`);
} else {
console.log(`Fehler: ${response.error}`);
}
}
Form State
type FormField<T> = {
value: T;
error?: string;
touched: boolean;
};
type LoginForm = {
email: FormField<string>;
password: FormField<string>;
rememberMe: FormField<boolean>;
};
let form: LoginForm = {
email: { value: "", touched: false },
password: { value: "", touched: false },
rememberMe: { value: false, touched: false }
};
// Validieren
function validateEmail(field: FormField<string>): FormField<string> {
if (!field.value.includes("@")) {
return { ...field, error: "Ungültige E-Mail" };
}
return { ...field, error: undefined };
}
Konfiguration
type DatabaseConfig = {
host: string;
port: number;
database: string;
credentials?: {
username: string;
password: string;
};
options?: {
ssl?: boolean;
timeout?: number;
poolSize?: number;
};
};
const dbConfig: DatabaseConfig = {
host: "localhost",
port: 5432,
database: "myapp",
credentials: {
username: "admin",
password: "secret"
},
options: {
ssl: true,
poolSize: 10
}
};
Excess Property Checks
TypeScript prüft auf zusätzliche Eigenschaften:
type Point = {
x: number;
y: number;
};
// Fehler: 'z' existiert nicht in Point
let point: Point = { x: 10, y: 20, z: 30 };
// Workaround mit Variable
let coords = { x: 10, y: 20, z: 30 };
let point2: Point = coords; // OK - nur x und y werden verwendet
Zusammenfassung
- Inline-Typen: Schnell für einmalige Verwendung
- Type Aliases: Wiederverwendbare, benannte Typen
- Optionale Properties: Mit
?markieren - Readonly: Unveränderliche Eigenschaften
- Index Signatures: Dynamische Schlüssel
- Nested Objects: Komplexe Strukturen
- Intersection: Typen kombinieren mit
&
Best Practices:
- Nutze Type Aliases für wiederverwendbare Typen
- Verwende optionale Properties statt
| undefined - Setze
readonlyfür Konfigurationen und Konstanten - Halte Objekt-Typen flach wenn möglich
Im nächsten Kapitel lernst du Union und Intersection Types im Detail!