Optionale Parameter & Standardwerte
Lerne wie du optionale Parameter und Standardwerte in TypeScript-Funktionen verwendest.
Aktualisiert:
Optionale Parameter & Standardwerte
Nicht jede Funktion braucht alle Parameter bei jedem Aufruf. TypeScript bietet optionale Parameter und Standardwerte für flexible Funktionssignaturen.
Optionale Parameter
Markiere Parameter mit ? als optional:
function greet(name: string, greeting?: string): string {
if (greeting) {
return `${greeting}, ${name}!`;
}
return `Hallo, ${name}!`;
}
greet("Max"); // "Hallo, Max!"
greet("Max", "Hi"); // "Hi, Max!"
Reihenfolge beachten
Optionale Parameter müssen nach required Parametern kommen:
// OK
function example(required: string, optional?: number): void {}
// Fehler!
function wrong(optional?: string, required: number): void {}
Optionale Parameter sind undefined
function log(message: string, prefix?: string): void {
// prefix ist string | undefined
console.log(prefix ? `[${prefix}] ${message}` : message);
}
// Oder mit nullish coalescing
function log2(message: string, prefix?: string): void {
const p = prefix ?? "LOG";
console.log(`[${p}] ${message}`);
}
Standardwerte (Default Parameters)
Standardwerte machen Parameter optional und geben einen Fallback:
function greet(name: string, greeting: string = "Hallo"): string {
return `${greeting}, ${name}!`;
}
greet("Max"); // "Hallo, Max!"
greet("Max", "Hi"); // "Hi, Max!"
Vorteile gegenüber optionalen Parametern
// Mit optionalem Parameter
function process1(data: string, count?: number): void {
const c = count ?? 1; // Manueller Fallback nötig
// ...
}
// Mit Standardwert - sauberer!
function process2(data: string, count: number = 1): void {
// count ist immer number, nie undefined
// ...
}
Standardwerte können Ausdrücke sein
// Funktion als Standardwert
function createId(): string {
return Math.random().toString(36).slice(2);
}
function createUser(name: string, id: string = createId()): void {
console.log(`User ${name} mit ID ${id}`);
}
createUser("Max"); // Neue zufällige ID
createUser("Anna", "custom-1"); // Eigene ID
Mit Objekten
type Options = {
timeout: number;
retries: number;
verbose: boolean;
};
function fetchData(
url: string,
options: Options = { timeout: 5000, retries: 3, verbose: false }
): void {
console.log(`Fetching ${url} with timeout ${options.timeout}`);
}
fetchData("https://api.example.com");
fetchData("https://api.example.com", { timeout: 10000, retries: 5, verbose: true });
Destrukturierung mit Standardwerten
Kombiniere Destrukturierung mit Standardwerten:
type Config = {
host?: string;
port?: number;
secure?: boolean;
};
function connect({
host = "localhost",
port = 3000,
secure = false
}: Config = {}): void {
const protocol = secure ? "https" : "http";
console.log(`Connecting to ${protocol}://${host}:${port}`);
}
connect(); // http://localhost:3000
connect({ port: 8080 }); // http://localhost:8080
connect({ host: "api.com", secure: true }); // https://api.com:3000
Komplexere Beispiele
type RequestOptions = {
method?: "GET" | "POST" | "PUT" | "DELETE";
headers?: Record<string, string>;
body?: unknown;
timeout?: number;
};
async function request(
url: string,
{
method = "GET",
headers = {},
body = undefined,
timeout = 5000
}: RequestOptions = {}
): Promise<Response> {
// TypeScript weiß: method ist immer ein String, nie undefined
console.log(`${method} ${url}`);
// Implementierung...
return fetch(url, { method, headers, body: JSON.stringify(body) });
}
// Verschiedene Aufrufe
request("/api/users");
request("/api/users", { method: "POST", body: { name: "Max" } });
request("/api/data", { timeout: 10000 });
undefined vs ausgelassen
Bei Standardwerten gibt es einen wichtigen Unterschied:
function greet(name: string = "Gast"): string {
return `Hallo, ${name}!`;
}
greet(); // "Hallo, Gast!" - Parameter ausgelassen
greet(undefined); // "Hallo, Gast!" - undefined triggert Standardwert
greet("Max"); // "Hallo, Max!"
Bei optionalen Parametern:
function log(message: string, level?: string): void {
console.log(level ? `[${level}]` : "", message);
}
log("Test"); // Parameter ausgelassen - level ist undefined
log("Test", undefined); // Explizit undefined - gleiches Ergebnis
log("Test", "INFO"); // "[INFO] Test"
Praktische Muster
Builder Pattern
type ButtonConfig = {
text: string;
variant?: "primary" | "secondary" | "danger";
size?: "small" | "medium" | "large";
disabled?: boolean;
onClick?: () => void;
};
function createButton({
text,
variant = "primary",
size = "medium",
disabled = false,
onClick = () => {}
}: ButtonConfig): HTMLButtonElement {
const button = document.createElement("button");
button.textContent = text;
button.className = `btn btn-${variant} btn-${size}`;
button.disabled = disabled;
button.addEventListener("click", onClick);
return button;
}
// Nur erforderliche Properties angeben
createButton({ text: "Klick mich" });
// Mit Anpassungen
createButton({
text: "Löschen",
variant: "danger",
onClick: () => console.log("Gelöscht!")
});
API Client
type ApiConfig = {
baseUrl: string;
timeout?: number;
headers?: Record<string, string>;
};
function createApiClient({
baseUrl,
timeout = 10000,
headers = { "Content-Type": "application/json" }
}: ApiConfig) {
return {
async get(endpoint: string) {
const response = await fetch(`${baseUrl}${endpoint}`, {
headers,
signal: AbortSignal.timeout(timeout)
});
return response.json();
},
async post(endpoint: string, data: unknown) {
const response = await fetch(`${baseUrl}${endpoint}`, {
method: "POST",
headers,
body: JSON.stringify(data),
signal: AbortSignal.timeout(timeout)
});
return response.json();
}
};
}
const api = createApiClient({ baseUrl: "https://api.example.com" });
Logger mit Optionen
type LogLevel = "debug" | "info" | "warn" | "error";
type LoggerConfig = {
prefix?: string;
minLevel?: LogLevel;
timestamp?: boolean;
};
function createLogger({
prefix = "App",
minLevel = "info",
timestamp = true
}: LoggerConfig = {}) {
const levels: LogLevel[] = ["debug", "info", "warn", "error"];
function shouldLog(level: LogLevel): boolean {
return levels.indexOf(level) >= levels.indexOf(minLevel);
}
function formatMessage(level: LogLevel, message: string): string {
const parts: string[] = [];
if (timestamp) parts.push(new Date().toISOString());
parts.push(`[${prefix}]`);
parts.push(`[${level.toUpperCase()}]`);
parts.push(message);
return parts.join(" ");
}
return {
debug: (msg: string) => shouldLog("debug") && console.log(formatMessage("debug", msg)),
info: (msg: string) => shouldLog("info") && console.log(formatMessage("info", msg)),
warn: (msg: string) => shouldLog("warn") && console.warn(formatMessage("warn", msg)),
error: (msg: string) => shouldLog("error") && console.error(formatMessage("error", msg))
};
}
const logger = createLogger();
const debugLogger = createLogger({ minLevel: "debug", prefix: "Debug" });
Zusammenfassung
Optionale Parameter (?):
- Typ wird zu
T | undefined - Müssen nach required Parametern kommen
- Benötigen manuelle Fallback-Logik
Standardwerte (= value):
- Machen Parameter automatisch optional
- Kein
undefinedim Typ - Können Ausdrücke oder Funktionsaufrufe sein
Best Practices:
- Bevorzuge Standardwerte über optionale Parameter
- Nutze Destrukturierung für Konfigurationsobjekte
- Halte Standardwerte einfach und vorhersehbar
Im nächsten Kapitel lernst du Function Overloads!