Menu

Omit en TypeScript : retirer des propriétés d'un type (exemples)

Omit<T, K> crée un type avec toutes les propriétés de T sauf les clés K. Découvrez Omit avec une ou plusieurs clés, la redéfinition du type d'une propriété, la suppression de la propriété à l'exécution, Omit vs Exclude et Pick, pourquoi Omit accepte des clés inexistantes, un Omit strict, et Omit sur les types union.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Omit<T, K> est un utility type intégré qui crée un type objet avec toutes les propriétés de T sauf les clés listées dans K. L'usage classique : un type User qui a un password, et une version publique qui n'en a pas.

PublicUser reste synchronisé avec User : ajoutez un champ à User et il apparaît aussi dans PublicUser, tandis que password reste exclu. Omit ne fonctionne que sur les types ; c'est la déstructuration dans toPublic qui retire la propriété de l'objet réel.

Omettre plusieurs clés

Le second argument est une union : listez autant de clés que nécessaire avec | :

« Le type sans les champs générés par le serveur » est le Omit le plus courant dans du vrai code : un seul type modèle, et Omit en dérive la forme d'entrée pour les formulaires de création et les requêtes d'API.

Comment Omit est défini

Omit est construit à partir de deux autres utility types :

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

Lisez-le de l'intérieur : keyof T est l'union de toutes les clés, Exclude<keyof T, K> retire de cette union les clés indésirables, et Pick garde les clés restantes. Ainsi, Omit<User, "password"> vaut Pick<User, "id" | "name" | "email">. Comme Pick parcourt les clés de T, les modificateurs readonly et ? des propriétés restantes sont conservés.

Remarquez la contrainte : K extends keyof any, et non K extends keyof T. Ce détail fait l'objet de la section suivante.

Omit ne vérifie pas que la clé existe

keyof any vaut string | number | symbol, donc Omit accepte absolument n'importe quelle clé, y compris une que T ne possède pas. Une faute de frappe compile et ne retire rien :

Aucune erreur nulle part, et le mot de passe part dans le JSON. Cette contrainte lâche a été choisie volontairement quand Omit a été ajouté dans TypeScript 3.5. Les raisons de l'équipe : dans du code générique, les clés omises ne viennent souvent pas de T (une fonction qui fusionne deux objets peut typer son argument rest comme Omit<T1, keyof T2>), Exclude ne contraint pas non plus son second paramètre, et une version contrainte aurait cassé beaucoup des types Omit écrits à la main que les projets avaient déjà. Pour le code de tous les jours, une version plus stricte attrape la faute de frappe :

index.ts(10,36): error TS2344: Type '"pasword"' does not satisfy the constraint 'keyof User'.
index.ts(11,7): error TS2741: Property 'password' is missing in type '{ id: number; name: string; }' but required in type 'PublicUser'.

La première erreur est celle qui compte : la clé est vérifiée par rapport à keyof User. La seconde en découle, puisque rien n'a été omis et que PublicUser exige toujours password. Corrigez l'orthographe en "password" et le code compile. Beaucoup de projets la définissent une fois dans un fichier de types partagé et l'utilisent à la place de Omit.

Redéfinir le type d'une propriété

Une interface ne peut pas en étendre une autre en changeant une propriété vers un type incompatible : interface ApiUser extends User { id: string } échoue avec error TS2430: Interface 'ApiUser' incorrectly extends interface 'User'. Omettez d'abord la propriété, puis redéclarez-la :

Avec un alias de type, la même chose s'écrit avec une intersection : type ApiUser = Omit<User, "id"> & { id: string }. Sans le Omit, l'intersection User & { id: string } donnerait à id le type number & string, c'est-à-dire never.

Omit sur les types union

Omit n'est pas distributif. Sur une union, il part du keyof de l'union entière, qui ne contient que les clés communes à tous les membres, donc les propriétés propres à chaque membre disparaissent :

index.ts(8,39): error TS2353: Object literal may only specify known properties, and 'radius' does not exist in type 'NewShape'.

NewShape est devenu { kind: "circle" | "square" }. Pour omettre dans chaque membre séparément, appliquez Omit dans un type conditionnel distributif :

T extends unknown ? ... : never est toujours vrai ; il n'est là que pour faire distribuer le type conditionnel sur l'union. La page sur les types conditionnels explique pourquoi cela fonctionne. Utilisez DistributiveOmit chaque fois que le type d'origine est une union discriminée.

Omettre une propriété imbriquée

Omit ne regarde que les clés de premier niveau, donc Omit<Settings, "editor.wordWrap"> ne retire rien (et, comme on l'a vu plus haut, ne se plaint pas). Pour retirer une propriété un niveau plus bas, omettez le parent et rajoutez-le avec son propre Omit :

Settings["editor"] est un indexed access type : il nomme le type de l'objet imbriqué pour que Omit puisse agir dessus.

Retirer des propriétés à l'exécution

Omit ne change que le type. Pour produire un objet sans les propriétés, retirez-les par déstructuration, ou écrivez un petit helper générique dont le type de retour est Omit :

Le helper contraint K à keyof T, donc une clé mal orthographiée est une erreur à l'appel. La copie est superficielle : les objets imbriqués sont partagés avec l'original.

Omit vs Pick vs Exclude

Agit surGardeExempleRésultat
Omit<T, K>types objetstoutes les propriétés sauf KOmit<User, "password">{ id; name; email }
Pick<T, K>types objetsseulement les propriétés de KPick<User, "id" | "name">{ id; name }
Exclude<U, M>types unionles membres de l'union non affectables à MExclude<"a" | "b" | "c", "a">"b" | "c"

Choisissez entre Omit et Pick selon ce qui doit se passer quand le type source grandit. Omit inclut automatiquement les nouvelles propriétés, ce qui convient à « tout sauf le secret ». Pick ne les inclut jamais, ce qui convient à « exactement ces champs » et reste plus sûr pour tout ce qui quitte votre serveur. Pick vérifie ses clés par rapport à keyof T ; Omit ne le fait pas.

Questions fréquentes

À quoi sert Omit en TypeScript ?

Omit<T, K> construit un nouveau type objet avec toutes les propriétés de T, sauf celles dont les clés sont dans K. Omit<User, "password"> est User sans password. Il ne change que le type ; il ne retire rien d'un objet à l'exécution.

Comment omettre plusieurs propriétés en TypeScript ?

Passez une union de clés en second argument : Omit<User, "password" | "createdAt" | "updatedAt">. Chaque clé de l'union est retirée.

Quelle est la différence entre Omit et Exclude ?

Omit retire des propriétés d'un type objet : Omit<{ a: 1; b: 2 }, "a"> vaut { b: 2 }. Exclude retire des membres d'un type union : Exclude<"a" | "b", "a"> vaut "b". Omit est implémenté avec Exclude : Pick<T, Exclude<keyof T, K>>.

Pourquoi Omit ne signale-t-il pas d'erreur pour une clé qui n'existe pas ?

Son paramètre de clés est contraint à keyof any (n'importe quel string, number ou symbol), et non à keyof T, donc une faute de frappe comme Omit<User, "pasword"> compile et ne retire rien. Définissez type StrictOmit<T, K extends keyof T> = Omit<T, K> pour obtenir une erreur sur les clés inconnues.

Comment supprimer une propriété d'un objet à l'exécution en TypeScript ?

Utilisez la déstructuration avec un élément rest : const { password, ...rest } = user;. TypeScript type rest comme l'objet sans password, la même forme que Omit<User, "password">, et la propriété a réellement disparu du nouvel objet.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER