Type Aliases
Lerne wie du mit Type Aliases eigene Typen in TypeScript definierst und wann du sie verwendest.
Aktualisiert:
Type Aliases
Type Aliases ermöglichen es dir, eigene Typnamen zu definieren. Sie sind ein fundamentales Feature in TypeScript, das deinen Code lesbarer und wartbarer macht.
Grundlagen
// Einfacher Type Alias
type UserId = number;
type UserName = string;
let id: UserId = 123;
let name: UserName = "Max";
// Für Objekte
type User = {
id: UserId;
name: UserName;
email: string;
};
const user: User = {
id: 1,
name: "Max",
email: "max@example.com"
};
Type Alias vs. direkte Annotation
// Ohne Type Alias - unübersichtlich
function processUser(user: { id: number; name: string; email: string }): void {
// ...
}
// Mit Type Alias - sauber
type User = {
id: number;
name: string;
email: string;
};
function processUser(user: User): void {
// ...
}
Arten von Type Aliases
Primitive Types
type ID = number | string;
type Age = number;
type Email = string;
type IsActive = boolean;
Object Types
type Point = {
x: number;
y: number;
};
type Circle = {
center: Point;
radius: number;
};
Union Types
type Status = "pending" | "active" | "completed" | "cancelled";
type Result = "success" | "error";
type Nullable<T> = T | null;
Intersection Types
type Timestamped = {
createdAt: Date;
updatedAt: Date;
};
type Identifiable = {
id: number;
};
type Entity = Timestamped & Identifiable;
Function Types
type Callback = () => void;
type EventHandler = (event: Event) => void;
type Comparator<T> = (a: T, b: T) => number;
type AsyncFunction<T> = () => Promise<T>;
Tuple Types
type Coordinates = [number, number];
type RGB = [number, number, number];
type NameAge = [string, number];
type Response = [boolean, string, unknown?];
Generische Type Aliases
// Einfaches Generic
type Container<T> = {
value: T;
};
const numContainer: Container<number> = { value: 42 };
const strContainer: Container<string> = { value: "hello" };
// Mit mehreren Type Parameters
type Pair<K, V> = {
key: K;
value: V;
};
const pair: Pair<string, number> = { key: "age", value: 25 };
// Mit Default Type
type Optional<T = string> = T | undefined;
let opt1: Optional = undefined; // Optional<string>
let opt2: Optional<number> = undefined; // Optional<number>
Bedingte Types
// Conditional Type
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
// Praktischer: Extract und Exclude
type EventType = "click" | "scroll" | "keydown" | "keyup";
type KeyEvents = Extract<EventType, "keydown" | "keyup">; // "keydown" | "keyup"
type NonKeyEvents = Exclude<EventType, "keydown" | "keyup">; // "click" | "scroll"
Mapped Types
// Alle Properties optional machen
type Partial<T> = {
[P in keyof T]?: T[P];
};
// Alle Properties readonly machen
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
// Beispiel
type User = {
id: number;
name: string;
email: string;
};
type PartialUser = Partial<User>;
// { id?: number; name?: string; email?: string; }
type ReadonlyUser = Readonly<User>;
// { readonly id: number; readonly name: string; readonly email: string; }
Template Literal Types
type Color = "red" | "green" | "blue";
type Size = "small" | "medium" | "large";
// Kombinieren mit Template Literals
type ColorSize = `${Color}-${Size}`;
// "red-small" | "red-medium" | "red-large" | "green-small" | ...
type EventName = `on${Capitalize<string>}`;
// Alle Strings die mit "on" beginnen und einen Großbuchstaben haben
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type Endpoint = `/api/${string}`;
type ApiRoute = `${HttpMethod} ${Endpoint}`;
Praktische Beispiele
API Types
type HttpStatus = 200 | 201 | 400 | 401 | 403 | 404 | 500;
type ApiResponse<T> = {
status: HttpStatus;
data?: T;
error?: string;
timestamp: number;
};
type User = { id: number; name: string };
type UserResponse = ApiResponse<User>;
type UsersResponse = ApiResponse<User[]>;
State Management
type LoadingState = {
status: "loading";
};
type SuccessState<T> = {
status: "success";
data: T;
};
type ErrorState = {
status: "error";
error: Error;
};
type AsyncState<T> = LoadingState | SuccessState<T> | ErrorState;
// Verwendung
type UserState = AsyncState<User>;
function renderUserState(state: UserState): string {
switch (state.status) {
case "loading":
return "Loading...";
case "success":
return `User: ${state.data.name}`;
case "error":
return `Error: ${state.error.message}`;
}
}
Form Handling
type InputType = "text" | "email" | "password" | "number";
type ValidationRule = {
required?: boolean;
minLength?: number;
maxLength?: number;
pattern?: RegExp;
custom?: (value: string) => boolean;
};
type FormField<T extends InputType> = {
type: T;
name: string;
label: string;
placeholder?: string;
validation?: ValidationRule;
defaultValue?: T extends "number" ? number : string;
};
type TextField = FormField<"text">;
type EmailField = FormField<"email">;
type NumberField = FormField<"number">;
Event System
type EventMap = {
click: { x: number; y: number };
keydown: { key: string; code: number };
scroll: { scrollTop: number; scrollLeft: number };
};
type EventName = keyof EventMap;
type EventData<E extends EventName> = EventMap[E];
type EventHandler<E extends EventName> = (data: EventData<E>) => void;
type EventListeners = {
[E in EventName]?: EventHandler<E>[];
};
Utility Pattern
// Null-safe Type
type Maybe<T> = T | null | undefined;
// Deep Readonly
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
// Non-nullable
type NonNullable<T> = T extends null | undefined ? never : T;
// Record shorthand
type StringRecord = Record<string, string>;
type NumberRecord = Record<string, number>;
// Function helpers
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
Zusammenfassung
Type Aliases können:
- Primitive Typen benennen
- Objekt-Shapes definieren
- Union und Intersection Types erstellen
- Funktionstypen beschreiben
- Mit Generics arbeiten
- Bedingte Logik enthalten
Best Practices:
- Verwende sprechende Namen
- Halte Types fokussiert
- Nutze Generics für Wiederverwendbarkeit
- Exportiere Types für Sharing
Im nächsten Kapitel lernst du die Unterschiede zwischen Interface und Type!