Zum Inhalt springen
TypeScript Fortgeschritten 35 min

Utility Types

Lerne die eingebauten Utility Types in TypeScript für häufige Typ-Transformationen.

Aktualisiert:

Utility Types

TypeScript bietet eine Reihe eingebauter Utility Types, die häufige Typ-Transformationen vereinfachen. Sie sind generische Typen, die auf bestehende Typen angewendet werden können.

Partial

Macht alle Properties optional:

type User = {
    id: number;
    name: string;
    email: string;
};

type PartialUser = Partial<User>;
// { id?: number; name?: string; email?: string; }

// Praktisch für Updates
function updateUser(id: number, updates: Partial<User>): User {
    const user = getUser(id);
    return { ...user, ...updates };
}

updateUser(1, { name: "Max" });  // Nur name ändern

Required

Macht alle Properties required:

type Config = {
    apiUrl?: string;
    timeout?: number;
    retries?: number;
};

type RequiredConfig = Required<Config>;
// { apiUrl: string; timeout: number; retries: number; }

function initialize(config: RequiredConfig): void {
    // Alle Properties sind garantiert vorhanden
    console.log(`API: ${config.apiUrl}, Timeout: ${config.timeout}`);
}

Readonly

Macht alle Properties readonly:

type User = {
    id: number;
    name: string;
};

type ReadonlyUser = Readonly<User>;
// { readonly id: number; readonly name: string; }

const user: ReadonlyUser = { id: 1, name: "Max" };
// user.name = "Anna";  // Fehler: Cannot assign to 'name'

// Praktisch für immutable State
function freeze<T>(obj: T): Readonly<T> {
    return Object.freeze(obj);
}

Pick<T, K>

Wählt bestimmte Properties aus:

type User = {
    id: number;
    name: string;
    email: string;
    password: string;
    createdAt: Date;
};

type PublicUser = Pick<User, "id" | "name" | "email">;
// { id: number; name: string; email: string; }

type Credentials = Pick<User, "email" | "password">;
// { email: string; password: string; }

Omit<T, K>

Schließt bestimmte Properties aus:

type User = {
    id: number;
    name: string;
    email: string;
    password: string;
};

type SafeUser = Omit<User, "password">;
// { id: number; name: string; email: string; }

type CreateUserInput = Omit<User, "id">;
// { name: string; email: string; password: string; }

// Kombiniert
type UpdateUserInput = Partial<Omit<User, "id">>;
// { name?: string; email?: string; password?: string; }

Record<K, T>

Erstellt einen Objekttyp mit bestimmten Keys:

type Role = "admin" | "user" | "guest";

type Permissions = Record<Role, string[]>;
// { admin: string[]; user: string[]; guest: string[]; }

const permissions: Permissions = {
    admin: ["read", "write", "delete"],
    user: ["read", "write"],
    guest: ["read"]
};

// Mit komplexerem Value-Typ
type UserRecord = Record<string, User>;

const users: UserRecord = {
    "user-1": { id: 1, name: "Max", email: "max@example.com", password: "..." },
    "user-2": { id: 2, name: "Anna", email: "anna@example.com", password: "..." }
};

Exclude<T, U>

Entfernt Typen aus einer Union:

type AllTypes = string | number | boolean | null | undefined;

type NonNullTypes = Exclude<AllTypes, null | undefined>;
// string | number | boolean

type Primitives = Exclude<AllTypes, boolean>;
// string | number | null | undefined

// Praktisch für Event-Typen
type Events = "click" | "scroll" | "keydown" | "keyup" | "focus" | "blur";
type MouseEvents = Exclude<Events, "keydown" | "keyup" | "focus" | "blur">;
// "click" | "scroll"

Extract<T, U>

Extrahiert Typen aus einer Union:

type AllTypes = string | number | boolean | null | undefined;

type Strings = Extract<AllTypes, string>;
// string

type Nullish = Extract<AllTypes, null | undefined>;
// null | undefined

// Mit Objekttypen
type Actions =
    | { type: "ADD"; payload: number }
    | { type: "REMOVE"; payload: number }
    | { type: "RESET" };

type AddAction = Extract<Actions, { type: "ADD" }>;
// { type: "ADD"; payload: number }

NonNullable

Entfernt null und undefined:

type MaybeString = string | null | undefined;

type DefinitelyString = NonNullable<MaybeString>;
// string

// Praktisch für Funktionsparameter
function process(value: string | null | undefined): void {
    if (value !== null && value !== undefined) {
        const definite: NonNullable<typeof value> = value;
        console.log(definite.toUpperCase());
    }
}

ReturnType

Extrahiert den Rückgabetyp einer Funktion:

function getUser() {
    return {
        id: 1,
        name: "Max",
        email: "max@example.com"
    };
}

type User = ReturnType<typeof getUser>;
// { id: number; name: string; email: string; }

// Auch für Arrow Functions
const createConfig = () => ({
    apiUrl: "https://api.example.com",
    timeout: 5000
});

type Config = ReturnType<typeof createConfig>;
// { apiUrl: string; timeout: number; }

Parameters

Extrahiert Parameter-Typen als Tuple:

function greet(name: string, age: number): string {
    return `Hello ${name}, you are ${age}`;
}

type GreetParams = Parameters<typeof greet>;
// [name: string, age: number]

// Nützlich für Wrapper-Funktionen
function logAndCall<F extends (...args: any[]) => any>(
    fn: F,
    ...args: Parameters<F>
): ReturnType<F> {
    console.log("Calling with:", args);
    return fn(...args);
}

logAndCall(greet, "Max", 25);  // Type-safe!

ConstructorParameters

Extrahiert Konstruktor-Parameter:

class User {
    constructor(
        public id: number,
        public name: string,
        public email: string
    ) {}
}

type UserParams = ConstructorParameters<typeof User>;
// [id: number, name: string, email: string]

function createUser(...args: UserParams): User {
    return new User(...args);
}

createUser(1, "Max", "max@example.com");

InstanceType

Extrahiert den Instanz-Typ eines Konstruktors:

class User {
    constructor(public name: string) {}
}

type UserInstance = InstanceType<typeof User>;
// User

function createInstance<T extends new (...args: any[]) => any>(
    constructor: T,
    ...args: ConstructorParameters<T>
): InstanceType<T> {
    return new constructor(...args);
}

const user = createInstance(User, "Max");
// user ist vom Typ User

ThisParameterType und OmitThisParameter

Arbeiten mit dem this Parameter:

function greet(this: { name: string }, greeting: string): string {
    return `${greeting}, ${this.name}!`;
}

type ThisType = ThisParameterType<typeof greet>;
// { name: string }

type WithoutThis = OmitThisParameter<typeof greet>;
// (greeting: string) => string

Awaited

Unwraps Promise-Typen:

type A = Awaited<Promise<string>>;
// string

type B = Awaited<Promise<Promise<number>>>;
// number

type C = Awaited<boolean | Promise<string>>;
// boolean | string

// Praktisch für async Funktionen
async function fetchUser(): Promise<{ id: number; name: string }> {
    return { id: 1, name: "Max" };
}

type User = Awaited<ReturnType<typeof fetchUser>>;
// { id: number; name: string }

Praktische Kombinationen

CRUD Operations

type User = {
    id: number;
    name: string;
    email: string;
    password: string;
    createdAt: Date;
    updatedAt: Date;
};

// Für Create - ohne id und Timestamps
type CreateUserInput = Omit<User, "id" | "createdAt" | "updatedAt">;

// Für Update - alles optional außer id
type UpdateUserInput = Partial<Omit<User, "id">> & Pick<User, "id">;

// Für Response - ohne Passwort
type UserResponse = Omit<User, "password">;

// Für Listen - nur wichtige Felder
type UserListItem = Pick<User, "id" | "name" | "email">;

Form State

type FormField<T> = {
    value: T;
    touched: boolean;
    error: string | null;
};

type FormState<T> = {
    [K in keyof T]: FormField<T[K]>;
};

type FormValues<T> = {
    [K in keyof T]: T[K] extends FormField<infer V> ? V : never;
};

type User = {
    name: string;
    email: string;
    age: number;
};

type UserFormState = FormState<User>;
type UserFormValues = FormValues<UserFormState>;

API Types

type ApiEndpoints = {
    "/users": { GET: User[]; POST: CreateUserInput };
    "/users/:id": { GET: User; PUT: UpdateUserInput; DELETE: void };
};

type GetEndpoints<T> = {
    [K in keyof T]: T[K] extends { GET: infer R } ? R : never;
};

type PostEndpoints<T> = {
    [K in keyof T]: T[K] extends { POST: infer R } ? R : never;
};

Zusammenfassung

Utility TypeBeschreibung
Partial<T>Alle Properties optional
Required<T>Alle Properties required
Readonly<T>Alle Properties readonly
Pick<T, K>Bestimmte Properties wählen
Omit<T, K>Properties ausschließen
Record<K, T>Objekt mit bestimmten Keys
Exclude<T, U>Aus Union entfernen
Extract<T, U>Aus Union extrahieren
NonNullable<T>null/undefined entfernen
ReturnType<T>Rückgabetyp einer Funktion
Parameters<T>Parameter einer Funktion
Awaited<T>Promise unwrappen

Diese Utility Types sind Bausteine für komplexere Typ-Transformationen. Kombiniere sie für mächtige, wiederverwendbare Typen!

Im nächsten Modul wenden wir alles Gelernte in praktischen Projekten an!

Zurück zum TypeScript Kurs