Tips & Tricks (Mis à jour: 02/06/2026)

Types utilitaires TypeScript avec Claude Code : guide pratique

Apprenez Pick, Omit, Partial, Record, ReturnType et Awaited avec des exemples exécutables pour Claude Code.

Types utilitaires TypeScript avec Claude Code : guide pratique

Les types utilitaires de TypeScript servent à transformer un type existant en un autre type adapté à un usage précis. Si vous copiez manuellement un type User en versions “vue publique”, “formulaire” et “mise à jour API”, ces copies finissent par diverger dès qu’un champ change. Claude Code peut aider à refactorer, mais vous devez comprendre l’intention de chaque outil pour relire correctement ce qu’il génère.

Ce guide explique Pick, Omit, Partial, Required, Readonly, Record, ReturnType et Awaited en termes simples. Il montre ensuite comment demander à Claude Code une conception de types réellement utilisable, avec des exemples copiables et exécutables. La référence officielle reste TypeScript Handbook Utility Types, et TSConfig strict aide à faire remonter les erreurs plus tôt.

Pour aller plus loin dans ClaudeCodeLab, lisez aussi les conseils TypeScript pratiques et le guide des génériques TypeScript.

Le modèle mental simple

Un type utilitaire est une opération sûre de “copie et remodelage” de type. Imaginez une feuille de calcul dupliquée, dans laquelle vous retirez des colonnes et rendez certaines cellules facultatives avant de l’utiliser dans un autre flux. Avec TypeScript, cette transformation est vérifiée avant l’exécution.

Pick<User, "id" | "name"> garde seulement id et name depuis User. Omit<User, "passwordHash"> conserve presque tout sauf passwordHash. Les deux sont proches, mais se lisent différemment. Utilisez Pick quand le type cible est volontairement petit, et Omit quand le type cible ressemble au type source avec quelques champs dangereux supprimés.

Partial<User> rend toutes les propriétés facultatives. C’est pratique pour les brouillons, PATCH et formulaires incomplets, mais cela peut rendre email facultatif au mauvais moment lors d’une création de compte. Required<User> fait l’inverse et force les propriétés facultatives à devenir obligatoires. Readonly<User> empêche la réassignation et documente qu’une configuration ne doit pas muter.

Record<Keys, Type> crée un dictionnaire avec des clés connues. ReturnType<typeof fn> extrait le type de retour d’une fonction. Awaited<Promise<T>> extrait le type de la valeur obtenue après await. Ensemble, ils permettent de dériver les types UI depuis les fonctions API.

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"]

Comparaison rapide

TypeCe qu’il faitUsage pratiquePoint de vigilance
Pick<T, K>Sélectionne certaines clésListes, profils publics, cartesLes clés non choisies sont absentes
Omit<T, K>Exclut certaines clésInputs de création, sorties publiques, logsNe supprime rien au runtime
Partial<T>Rend toutes les clés facultativesBrouillons, PATCH, formulaires partielsSuperficiel
Required<T>Rend toutes les clés obligatoiresDonnées validées avant sauvegardePeut imposer trop de champs
Readonly<T>Empêche la réassignationConfiguration, permissions, constantesLes objets imbriqués demandent plus d’attention
Record<K, T>Crée un dictionnaire à clés fixesDroits par rôle, libellés, prixRecord<string, T> est souvent trop large
ReturnType<T>Extrait le retour d’une fonctionSynchroniser API et UIUtiliser typeof functionName
Awaited<T>Extrait la valeur résolue d’une PromiseRésultats de fonctions asyncCe n’est pas un await runtime

Collez ce tableau dans Claude Code et demandez-lui de vérifier si chaque type utilitaire correspond à son usage. Dans un projet strict: true, les types vagues cassent plus tôt, ce qui est préférable.

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "skipLibCheck": true
  }
}

Cas 1 : dériver les types UI et formulaire depuis User

Les écrans d’administration ont souvent besoin de plusieurs versions d’une même entité. Le type base de données, le type public et le type formulaire ne doivent pas être trois copies manuelles. Gardez un type source et dérivez le reste avec les types utilitaires.

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);

La consigne à Claude Code doit séparer ce qui reste, ce qui disparaît et ce qui devient obligatoire.

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.

En production, ajoutez une validation runtime, par exemple avec Zod. Les types utilitaires vérifient la forme avant exécution ; ils ne prouvent pas que les données soumises par l’utilisateur sont fiables.

Cas 2 : verrouiller les fonctionnalités de plan avec Record

Plans tarifaires, rôles et tables d’état conviennent très bien à Record. Le compilateur peut signaler un plan team manquant ou une faute dans prioritySupport.

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 documente que cette matrice ne doit pas être modifiée. Comme il est superficiel par défaut, l’exemple marque aussi le Record interne en lecture seule. Pour des structures plus profondes, utilisez as const ou un helper deep readonly propre au projet.

Cas 3 : réutiliser les résultats API avec ReturnType et Awaited

Quand les types du client API et de l’interface sont écrits séparément, chaque changement de réponse coûte cher. ReturnType et Awaited permettent de dériver le type depuis la fonction async réelle.

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();

Si la fonction API est la frontière fiable, demandez à Claude Code de ne pas recopier un type de réponse à la main. Pour une API externe ou une entrée utilisateur, gardez une validation runtime et une gestion d’erreur.

Cas 4 : appliquer Partial au bon niveau

Partial<T> est superficiel. Il ne rend pas automatiquement facultatifs les champs d’un objet imbriqué, ce qui piège souvent les débutants.

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 } }));

Avec seulement ProfilePatch = Partial<Profile>, mettre à jour settings exigerait encore l’objet settings complet. Dans une équipe mixte, un type concret comme celui-ci est souvent plus lisible qu’un deep partial générique trop malin.

Échecs concrets à éviter

Omit enlève une clé du type, pas de l’objet au runtime. Si vous renvoyez des logs ou une réponse publique, retirez réellement la valeur sensible.

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> est souvent trop large pour des règles métier. Si les clés sont connues, préférez une union comme type Plan = "free" | "pro" | "team".

Required<T> peut rendre un formulaire inutilement strict s’il est appliqué trop tôt. Utilisez-le après validation, quand les données sont réellement complètes.

Awaited<T> décrit seulement le type résolu d’une Promise. Il ne déclenche aucune attente au runtime ; il faut toujours await ou .then(). Si cette nuance disparaît, Claude Code peut nettoyer les types tout en oubliant loading et erreurs.

Prompt de revue pour Claude Code

Après l’implémentation, demandez une revue orientée risques.

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?

Ce cadrage vise la prévention des défauts plutôt que la beauté des types. Masa l’a rencontré dans un petit écran d’administration : Partial utilisé partout rendait un email vide acceptable jusqu’à la sauvegarde. Séparer “brouillon”, “création” et “enregistré” en types dérivés a rendu les patchs de Claude Code beaucoup plus faciles à relire.

Conclusion

Les types utilitaires TypeScript ne sont pas de la gymnastique de types. Ce sont des outils pratiques pour exprimer la différence entre données publiques, brouillons, entrées validées, configuration fixe et résultats async sans dupliquer les définitions. Utilisez Pick et Omit pour contrôler les champs, Partial et Required pour modéliser les étapes, Readonly et Record pour protéger la configuration, puis ReturnType et Awaited pour éviter les types API dupliqués.

ClaudeCodeLab aide les équipes à appliquer Claude Code à l’architecture TypeScript, aux CMS de contenu, aux outils internes et aux funnels monétisés. Si votre projet a des types mais continue à produire des erreurs évitables, demandez une formation et consultation Claude Code.

J’ai vérifié les exemples de cet article avec une approche TypeScript stricte. Le gain le plus net vient de ReturnType et Awaited : quand une réponse API change, les endroits à corriger dans l’UI apparaissent plus vite. La limite importante reste Omit : il ne supprime jamais les secrets au runtime, donc les fonctions de réponse publique doivent retirer les propriétés explicitement.

#Claude Code #TypeScript #utility types #type safety #qualité du code
Gratuit

PDF gratuit: cheatsheet Claude Code

Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.

Nous protégeons vos données et n'envoyons pas de spam.

Masa

À propos de l'auteur

Masa

Ingénieur spécialisé dans les workflows pratiques avec Claude Code.