TypeScript Utility Types mit Claude Code: praxisnaher Einstieg
Lerne Pick, Omit, Partial, Record, ReturnType und Awaited mit lauffähigen Claude-Code-Beispielen.
TypeScript Utility Types sind Werkzeuge, mit denen du aus einem vorhandenen Typ einen neuen Typ für einen konkreten Zweck ableitest.
Wenn du einen User-Typ von Hand in Varianten für öffentliche Ansicht, Formular und API-Update kopierst, laufen diese Kopien auseinander, sobald ein Feld geändert wird.
Claude Code kann beim Refactoring helfen, aber du musst die Absicht der einzelnen Utility Types kennen, um den Vorschlag sauber zu prüfen.
Dieser Leitfaden erklärt Pick, Omit, Partial, Required, Readonly, Record, ReturnType und Awaited in einfacher Sprache.
Danach zeigt er mit kopierbaren Beispielen, wie du Claude Code zu praktischer Typmodellierung anleitest.
Die offizielle Grundlage ist das TypeScript Handbook zu Utility Types; für frühe Fehler nutze zusätzlich TSConfig strict.
Passend dazu findest du bei ClaudeCodeLab praktische TypeScript-Tipps und den TypeScript-Generics-Leitfaden.
Das einfache Denkmodell
Ein Utility Type ist eine sichere Operation zum “Kopieren und Umformen” eines Typs. Stell dir vor, du duplizierst eine Tabelle, blendest Spalten aus und machst einige Spalten optional, bevor du sie in einem anderen Prozess verwendest. TypeScript prüft diese Umformung vor der Ausführung.
Pick<User, "id" | "name"> nimmt nur id und name aus User.
Omit<User, "passwordHash"> behält fast alles, entfernt aber passwordHash.
Beide sind ähnlich, aber die Lesrichtung ist anders.
Nutze Pick, wenn der Zieltyp bewusst klein ist, und Omit, wenn der Zieltyp fast dem Ursprung entspricht und nur wenige gefährliche Felder fehlen sollen.
Partial<User> macht alle Eigenschaften optional.
Das passt für Entwürfe, PATCH-Requests und Formulare in Bearbeitung, kann aber bei der Erstellung versehentlich ein notwendiges email optional machen.
Required<User> macht optionale Eigenschaften wieder verpflichtend.
Readonly<User> verhindert Neuzuweisungen und dokumentiert, dass Konfiguration oder Stammdaten nicht mutieren sollen.
Record<Keys, Type> erzeugt ein Dictionary mit bekannten Schlüsseln.
ReturnType<typeof fn> extrahiert den Rückgabetyp einer Funktion.
Awaited<Promise<T>> extrahiert den Werttyp nach await.
Zusammen halten Awaited und ReturnType API-Funktionen und UI-Typen synchron.
flowchart LR
A["Source type: User"] --> B["Pick: public view"]
A --> C["Omit: remove secrets"]
A --> D["Partial: update input"]
A --> E["Required: validated input"]
A --> F["Readonly: fixed settings"]
G["Function"] --> H["ReturnType"]
I["Promise"] --> J["Awaited"]
Schneller Vergleich
| Typ | Wirkung | Praktischer Einsatz | Achtung |
|---|---|---|---|
Pick<T, K> | Wählt bestimmte Schlüssel aus | Listen, öffentliche Profile, Karten | Nicht gewählte Felder sind nicht verfügbar |
Omit<T, K> | Entfernt bestimmte Schlüssel | Create-Inputs, öffentliche Ausgabe, Logs | Entfernt keine Runtime-Werte |
Partial<T> | Macht alle Schlüssel optional | Entwürfe, PATCH, Teilformulare | Nur oberflächlich |
Required<T> | Macht alle Schlüssel verpflichtend | Validierte Daten vor dem Speichern | Kann zu früh zu streng sein |
Readonly<T> | Verhindert Neuzuweisung | Einstellungen, Berechtigungen, Konstanten | Verschachtelte Objekte brauchen Zusatzschutz |
Record<K, T> | Erzeugt ein Dictionary mit festen Schlüsseln | Rollenrechte, Labels, Preise | Record<string, T> ist oft zu breit |
ReturnType<T> | Holt den Rückgabetyp einer Funktion | API- und UI-Typen synchronisieren | typeof functionName verwenden |
Awaited<T> | Holt den aufgelösten Promise-Wert | Ergebnisse von async-Funktionen | Kein Runtime-await |
Gib diese Tabelle Claude Code und bitte um eine Prüfung, ob die Typwahl zum Zweck passt.
In Projekten mit strict: true fallen unklare Typen früher auf, was genau der gewünschte Effekt ist.
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"skipLibCheck": true
}
}
Use Case 1: UI- und Formular-Typen aus User ableiten
Admin-Oberflächen brauchen oft mehrere Varianten derselben Entität. Datenbanktyp, öffentlicher Typ und Formularinput sollten keine handgepflegten Kopien sein. Halte einen Quelltyp und leite die Varianten mit Utility Types ab.
type UserRole = "admin" | "editor" | "viewer";
interface User {
id: string;
name: string;
email: string;
role: UserRole;
bio: string;
passwordHash: string;
createdAt: Date;
updatedAt: Date;
}
type PublicUser = Pick<User, "id" | "name" | "role" | "bio">;
type UserDraft = Partial<Omit<User, "id" | "passwordHash" | "createdAt" | "updatedAt">>;
type CreateUserInput =
Required<Pick<User, "name" | "email" | "role">> &
Partial<Pick<User, "bio">>;
function buildCreatePayload(input: CreateUserInput): Omit<User, "id" | "createdAt" | "updatedAt"> {
return {
name: input.name,
email: input.email,
role: input.role,
bio: input.bio ?? "",
passwordHash: "hashed-by-server",
};
}
const publicUser: PublicUser = {
id: "u_001",
name: "Masa",
role: "admin",
bio: "Claude Code workflow designer",
};
const draft: UserDraft = {
name: "Draft user",
bio: "Saved before email is confirmed",
};
console.log(publicUser);
console.log(buildCreatePayload({ name: "Aki", email: "aki@example.com", role: "editor" }));
console.log(draft);
Die Anweisung an Claude Code sollte trennen, was bleibt, was entfernt wird und wann etwas verpflichtend ist.
Create public display, form draft, and create-API types from the User type.
Do not expose passwordHash.
For creation, require only name, email, and role. Keep bio optional.
Use Pick/Omit/Partial/Required and briefly explain why each utility type is used.
In Produktion gehören Runtime-Validierung und Fehlerbehandlung dazu, etwa mit Zod. Utility Types prüfen die Form vor der Ausführung, beweisen aber nicht, dass Benutzereingaben vertrauenswürdig sind.
Use Case 2: Plan-Features mit Record fixieren
Preispläne, Rollen und Status-Tabellen passen sehr gut zu Record.
Der Compiler kann melden, wenn der Plan team fehlt oder prioritySupport falsch geschrieben ist.
type Plan = "free" | "pro" | "team";
type Feature = "exportPdf" | "inviteMember" | "prioritySupport";
const featureMatrix: Readonly<Record<Plan, Readonly<Record<Feature, boolean>>>> = {
free: {
exportPdf: false,
inviteMember: false,
prioritySupport: false,
},
pro: {
exportPdf: true,
inviteMember: false,
prioritySupport: false,
},
team: {
exportPdf: true,
inviteMember: true,
prioritySupport: true,
},
};
function canUse(plan: Plan, feature: Feature): boolean {
return featureMatrix[plan][feature];
}
console.log(canUse("pro", "exportPdf"));
console.log(canUse("free", "prioritySupport"));
Readonly hält fest, dass diese Matrix nicht zur Laufzeit verändert werden soll.
Da es standardmäßig oberflächlich ist, markiert das Beispiel auch das innere Record als readonly.
Für tiefere Strukturen können as const oder ein projektspezifischer Deep-Readonly-Helfer sinnvoll sein.
Use Case 3: API-Ergebnisse mit ReturnType und Awaited wiederverwenden
Wenn API-Client-Typen und UI-Typen getrennt geschrieben werden, werden Response-Änderungen teuer.
ReturnType plus Awaited leitet den Typ direkt aus der async-Funktion ab.
async function fetchInvoice(invoiceId: string) {
return {
id: invoiceId,
status: "paid" as const,
amount: 48000,
currency: "JPY" as const,
paidAt: new Date("2026-06-02T10:00:00+09:00"),
};
}
type Invoice = Awaited<ReturnType<typeof fetchInvoice>>;
type InvoiceSummary = Pick<Invoice, "id" | "status" | "amount" | "currency">;
function formatInvoice(invoice: InvoiceSummary): string {
return `${invoice.id}: ${invoice.amount.toLocaleString()} ${invoice.currency} (${invoice.status})`;
}
async function main() {
const invoice = await fetchInvoice("inv_20260602");
console.log(formatInvoice(invoice));
}
main();
Wenn die API-Funktion die verlässliche Grenze ist, bitte Claude Code darum, keinen zweiten Response-Typ von Hand zu schreiben. Bei externen APIs oder Benutzereingaben brauchst du weiterhin Runtime-Validierung und Fehlerzustände.
Use Case 4: Partial auf der richtigen Ebene einsetzen
Partial<T> ist oberflächlich.
Es macht verschachtelte Felder nicht automatisch optional, was häufig zu Anfängerfehlern führt.
interface Profile {
id: string;
displayName: string;
settings: {
emailNotification: boolean;
smsNotification: boolean;
};
}
type ProfilePatch =
Omit<Partial<Profile>, "settings"> & {
settings?: Partial<Profile["settings"]>;
};
function patchProfile(current: Profile, patch: ProfilePatch): Profile {
return {
...current,
...patch,
settings: {
...current.settings,
...patch.settings,
},
};
}
const profile: Profile = {
id: "p_001",
displayName: "Masa",
settings: {
emailNotification: true,
smsNotification: false,
},
};
console.log(patchProfile(profile, { settings: { smsNotification: true } }));
Mit nur ProfilePatch = Partial<Profile> müsste ein Update von settings weiterhin das vollständige settings-Objekt liefern.
Für Teams mit Einsteigern ist ein konkreter Patch-Typ oft wartbarer als ein cleverer generischer Deep Partial.
Konkrete Fehlerfälle
Omit entfernt einen Schlüssel aus dem Typ, nicht aus dem Objekt zur Laufzeit.
Wenn du Logs oder öffentliche API-Antworten zurückgibst, musst du sensible Werte wirklich entfernen.
interface Account {
id: string;
email: string;
passwordHash: string;
}
type SafeAccount = Omit<Account, "passwordHash">;
function toSafeAccount(account: Account): SafeAccount {
const { passwordHash, ...safeAccount } = account;
return safeAccount;
}
console.log(toSafeAccount({
id: "a_001",
email: "masa@example.com",
passwordHash: "secret",
}));
Record<string, T> ist für Geschäftsregeln oft zu weit.
Wenn die erlaubten Schlüssel bekannt sind, verwende eine Union wie type Plan = "free" | "pro" | "team".
Required<T> macht Formulare schnell zu streng, wenn du es zu früh anwendest.
Nutze es nach der Validierung, wenn die Daten wirklich vollständig sind.
Awaited<T> beschreibt nur den aufgelösten Typ einer Promise.
Es wartet nicht zur Laufzeit; dafür brauchst du weiterhin await oder .then().
Wenn diese Grenze unklar ist, bereinigt Claude Code eventuell nur die Typen und vergisst Loading- und Error-States.
Review-Prompt für Claude Code
Nach der Implementierung solltest du keine vage Aufräum-Anweisung geben, sondern eine risikoorientierte Prüfung anfordern.
Review this TypeScript type design.
1. Are Pick/Omit/Partial/Required/Readonly/Record matched to their use cases?
2. Are secrets removed at runtime, not only with Omit?
3. Does Partial make create inputs too loose?
4. Do ReturnType and Awaited reduce duplicated API types?
5. Are any vague any or broad string types left under strict settings?
Dieser Rahmen fokussiert auf Fehlervermeidung.
Masa hatte in einem kleinen Admin-Screen genau dieses Problem: Partial wurde überall genutzt, sodass eine leere email bis zum Speichern akzeptabel wirkte.
Nachdem “Entwurf”, “Erstellung” und “gespeichert” getrennte abgeleitete Typen wurden, ließen sich Claude-Code-Patches deutlich leichter prüfen.
Fazit
TypeScript Utility Types sind keine Typ-Akrobatik.
Sie sind praktische Werkzeuge, um öffentliche Daten, Entwürfe, validierte Inputs, feste Konfiguration und async API-Ergebnisse ohne doppelte Definitionen zu modellieren.
Nutze Pick und Omit für Felder, Partial und Required für Workflow-Stufen, Readonly und Record für Konfiguration und ReturnType plus Awaited gegen doppelte API-Typen.
ClaudeCodeLab unterstützt Teams bei TypeScript-Architektur mit Claude Code, Content-CMS, internen Tools und monetarisierten Funnels. Wenn dein Projekt zwar Typen hat, aber trotzdem vermeidbare Fehler produziert, buche Claude Code Training und Consulting.
Ich habe die Beispiele in diesem Artikel mit einer strikten TypeScript-Haltung geprüft.
Der größte praktische Gewinn kam von ReturnType plus Awaited: Bei Response-Änderungen werden UI-Anpassungen schneller sichtbar.
Die wichtige Einschränkung bleibt Omit: Es entfernt Geheimnisse nie zur Laufzeit, öffentliche Response-Funktionen brauchen also weiterhin explizites Entfernen von Eigenschaften.
Kostenloses PDF: Claude-Code-Cheatsheet
E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.
Wir schützen Ihre Daten und senden keinen Spam.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Permission Safety Ladder: Zugriff kontrolliert erweitern
Von read-only zu begrenzten Änderungen, Prüfbefehlen und Deploy-Checks mit klarer Kontrolle.
Claude Code Small PR Proof Pack: kleine Änderungen reviewbar machen
Ein Proof Pack für Claude-Code-PRs: Diff, Checks, öffentliche URL, CTA-Pfad und Rollback.
Claude-Code-Review-Gate vor dem Commit
Vor dem Commit mit Claude Code prüfen: Diff, Build, öffentliche URL, Gumroad-Links, Beratung-CTA, fehlende Tests und fremde Dateien.