Zum Inhalt springen
TypeScript Anfänger 30 min

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 readonly für Konfigurationen und Konstanten
  • Halte Objekt-Typen flach wenn möglich

Im nächsten Kapitel lernst du Union und Intersection Types im Detail!

Zurück zum TypeScript Kurs