1 points par GN⁺ 2025-05-20 | 1 commentaires | Partager sur WhatsApp
  • Zod 4 est publié en version stable après un an de développement ; il corrige les limites de conception de Zod 3 et améliore fortement les performances, la taille du bundle et l’efficacité de compilation TypeScript
  • Zod 3, sorti en mai 2021, est passé de 2 700 étoiles GitHub et 600 000 téléchargements hebdomadaires à 37,8k étoiles et 31 millions de téléchargements hebdomadaires aujourd’hui ; après 24 versions mineures, les principales améliorations nécessitaient des changements incompatibles
  • Dans les benchmarks, le parsing de chaînes est 14 fois plus rapide, celui des tableaux 7 fois plus rapide et celui des objets 6,5 fois plus rapide ; les instanciations de types par tsc passent aussi de plus de 25 000 à environ 175 dans un exemple simple
  • La taille du bundle cœur passe, en gzip, de 12.47kb pour Zod 3 à 5.36kb pour la version standard de Zod 4 ; Zod Mini, une API fonctionnelle compatible avec le tree shaking, descend jusqu’à 1.88kb
  • Les nouveautés incluent la conversion en JSON Schema, un registre de métadonnées, l’inférence de types d’objets récursifs, l’internationalisation, le pretty-printing des erreurs, les types template literal, z.stringbool(), un paramètre error unifié et un z.discriminatedUnion() amélioré

Pourquoi Zod 4 est une nouvelle version majeure

  • Zod 4 devient stable après un an de développement actif et implémente des fonctionnalités longtemps demandées sur une base plus rapide, plus légère et plus efficace pour tsc
  • Zod v3.0 est sorti en mai 2021 ; à l’époque, il comptait 2 700 étoiles GitHub et 600 000 téléchargements hebdomadaires
  • Aujourd’hui, Zod affiche 37,8k étoiles GitHub et 31 millions de téléchargements hebdomadaires
    • Il y a six semaines, lors de la bêta, les téléchargements hebdomadaires étaient de 23 millions
  • Après 24 versions mineures, la base de code de Zod 3 a atteint ses limites, et les fonctionnalités et améliorations les plus demandées nécessitaient des changements incompatibles
  • Zod 4 ferme 9 des 10 issues publiques ayant reçu le plus de votes

Performances de parsing et efficacité de compilation TypeScript

  • Zod 4 fournit des benchmarks exécutables directement depuis le dépôt
  • Améliorations des performances de parsing :
    • Parsing de chaînes : 14 fois plus rapide
    • Parsing de tableaux : 7 fois plus rapide
    • Parsing d’objets : 6,5 fois plus rapide
  • Le benchmark de parsing d’objets exécute le benchmark des bibliothèques de validation de Moltar
  • Avec tsc --extendedDiagnostics, les instanciations de types diminuent fortement lors de la compilation d’un fichier simple
    • Avec "zod/v3" : plus de 25 000
    • Avec "zod/v4" : environ 175
  • Zod 4 évite l’explosion des instanciations en repensant et simplifiant les génériques de ZodObject et des autres classes de schémas
  • Le motif consistant à chaîner plusieurs fois .extend() et .omit() prenait 4000ms à compiler avec Zod 3, et un appel .extend() supplémentaire pouvait provoquer une erreur "Possibly infinite"
  • Le même motif compile en 400ms avec Zod 4, soit 10 fois plus vite
  • À l’avenir, utilisé avec le compilateur tsgo, Zod 4 pourrait faire évoluer les performances dans l’éditeur vers des schémas et bases de code encore plus grands

Taille du bundle et Zod Mini

  • Un simple script de validation z.boolean() est bundlé avec rollup pour comparer la taille du bundle cœur
  • Taille du bundle cœur en gzip :
    • Zod 3 : 12.47kb
    • Version standard de Zod 4 : 5.36kb
  • Le bundle cœur de la version standard de Zod 4 est environ 57 % plus petit que celui de Zod 3, soit une réduction d’un facteur 2,3
  • L’API de Zod centrée sur les méthodes est fondamentalement difficile à tree shaker, et même un simple script z.boolean() embarque aussi des implémentations de méthodes inutilisées comme .optional() et .array()
  • Zod Mini fournit une API fonctionnelle, compatible avec le tree shaking, correspondant 1:1 à zod
    • Là où Zod utilise des méthodes, Zod Mini utilise généralement des fonctions wrapper
    • Les méthodes de parsing sont identiques entre Zod et Zod Mini
    • Une méthode générique .check() permet d’ajouter des raffinements
  • Zod standard reste recommandé pour la plupart des cas d’usage, tandis que les projets soumis à des contraintes de taille de bundle exceptionnellement strictes peuvent envisager Zod Mini
  • Avec zod/mini, la taille du bundle gzip est de 1.88kb
    • Soit 85 % de moins que Zod 3, une réduction d’un facteur 6,6
    • Tableau comparatif : Zod 3 12.47kb, Zod 4 standard 5.36kb, Zod 4 Mini 1.88kb
  • Plus de détails sont disponibles dans la documentation zod/mini

Métadonnées et JSON Schema

  • Zod 4 introduit un nouveau système pour ajouter aux schémas des métadonnées fortement typées
  • Les métadonnées sont stockées non pas dans le schéma lui-même, mais dans un registre de schémas qui associe les schémas à des typed metadata
  • Il est possible de créer un registre avec z.registry(), et la méthode .register() des schémas permet aussi un enregistrement pratique
  • Zod exporte un registre global, z.globalRegistry, qui accepte les métadonnées courantes compatibles JSON Schema
  • La méthode .meta() ajoute facilement un schéma à z.globalRegistry
  • Pour la compatibilité avec Zod 3, .describe() reste disponible, mais .meta() est recommandée dans Zod 4
  • Zod 4 fournit une conversion JSON Schema first-party via z.toJSONSchema()
  • Les métadonnées de z.globalRegistry sont automatiquement incluses dans la sortie JSON Schema
  • Les informations de personnalisation du JSON Schema généré se trouvent dans la documentation JSON Schema

Nouvelles expressions de schémas et fonctionnalités de typage

  • Zod 4 peut correctement inférer les types d’objets récursifs
    • Il permet d’exprimer des types récursifs et des types mutuellement récursifs
    • Contrairement au motif de types récursifs de Zod 3, aucun cast de type n’est nécessaire
    • Le schéma obtenu est une instance ZodObject standard et peut utiliser toutes ses méthodes
  • Un schéma File a été ajouté pour valider les instances de File
  • z.templateLiteral() exprime les types template literal de TypeScript
    • Les types de schémas Zod convertibles en chaîne stockent une expression régulière interne
    • Les cibles incluent les chaînes, les formats de chaînes comme z.email(), les nombres, les boolean, les bigint, les enum, les literal, undefined/optional, null/nullable et d’autres template literal
    • Le constructeur z.templateLiteral les concatène en une super-regex
    • Les formats de chaînes comme z.email() sont bien appliqués, mais les custom refinement ne le sont pas
    • Plus de détails dans la documentation sur les template literal
  • De nouveaux formats numériques représentant des entiers de largeur fixe et des types à virgule flottante ont été ajoutés
    • Ils renvoient une instance ZodNumber avec les contraintes inclusive minimum/maximum appropriées déjà ajoutées
  • Des formats numériques bigint dépassant la plage représentable de manière sûre par un number JavaScript ont aussi été ajoutés
    • Ils renvoient une instance ZodBigInt avec les contraintes inclusive minimum/maximum appropriées déjà ajoutées
  • z.literal() peut désormais accepter plusieurs valeurs de façon optionnelle

Erreurs, internationalisation et formats de chaînes

  • Zod 4 introduit une nouvelle API locales pour traduire globalement les messages d’erreur dans plusieurs langues
  • La liste complète des locales prises en charge se trouve dans Customizing errors et sera mise à jour à mesure que des langues seront ajoutées
  • Zod implémente une fonction de haut niveau z.prettifyError qui transforme une ZodError en chaîne dans un format convivial
    • Le format actuel n’est pas configurable
    • Il pourra changer à l’avenir
    • Si vous utilisez déjà zod-validation-error, vous pouvez continuer à l’utiliser
  • Tous les formats de chaînes, dont email, sont promus en fonctions de haut niveau du module z
    • C’est plus concis et plus favorable au tree shaking
    • Les API équivalentes sous forme de méthodes, comme z.string().email(), restent utilisables mais sont deprecated
    • Elles seront supprimées dans la prochaine version majeure
  • L’API z.email() prend en charge les custom regular expressions
    • Il n’existe pas de regex email canonique unique, et chaque application peut choisir des critères plus stricts ou plus souples
    • Zod exporte quelques expressions régulières courantes par commodité

Conversion de booléens et simplification de la personnalisation des erreurs

  • L’ancien z.coerce.boolean() est une API simple qui convertit les valeurs falsy en false et les valeurs truthy en true
    • false, undefined, null, 0, "", NaN, etc. deviennent false
    • Ce comportement est cohérent avec les autres API z.coerce
  • Pour une coercition de boolean plus élaborée façon variables d’environnement, Zod 4 introduit z.stringbool()
  • La plupart des changements incompatibles de Zod 4 concernent l’API de personnalisation des erreurs
  • La personnalisation des erreurs est unifiée dans un seul paramètre error
    • message est remplacé par error
    • Le paramètre message reste pris en charge mais est deprecated
    • invalid_type_error et required_error sont remplacés par la syntaxe fonctionnelle de error
    • errorMap est également remplacé par la syntaxe fonctionnelle de error

Composabilité, raffinements et transformations

  • z.discriminatedUnion() prend en charge plusieurs types de schémas qui ne l’étaient pas auparavant
    • Cela inclut les unions et les pipes
    • Une discriminated union peut être utilisée comme membre d’une autre discriminated union, ce qui la rend composable
  • Dans Zod 3, les raffinements étaient stockés dans la classe ZodEffects, qui enveloppait le schéma d’origine
    • Cette structure rendait peu pratique la combinaison de .refine() avec d’autres méthodes de schéma comme .min()
  • Dans Zod 4, les raffinements sont stockés à l’intérieur du schéma, ce qui permet d’utiliser naturellement .refine() avec les autres méthodes de schéma
  • La nouvelle méthode .overwrite() exprime une transformation qui ne change pas l’inferred type
    • .transform() produit un type de sortie qui n’est pas introspectable à l’exécution, et la fonction de transformation peut renvoyer n’importe quoi : c’est une boîte noire
    • Il n’existe donc pas de moyen sûr de la convertir en JSON Schema
    • .overwrite() renvoie une instance de la classe d’origine
    • La fonction overwrite est stockée comme un raffinement et ne modifie pas l’inferred type
  • Les méthodes existantes .trim(), .toLowerCase() et .toUpperCase() ont été réimplémentées avec .overwrite()

Une base pour les auteurs de bibliothèques

  • L’ajout de Zod Mini a entraîné la création du sous-paquet zod/v4/core, qui contient les fonctionnalités cœur partagées par Zod et Zod Mini
  • zod/v4/core fait évoluer Zod d’une simple bibliothèque vers une base de validation rapide pouvant être intégrée à d’autres bibliothèques
  • Si vous créez une bibliothèque de schémas, vous pouvez vous appuyer sur zod/v4/core en vous inspirant des implémentations de Zod et Zod Mini
  • Un guide For library authors est fourni pour les auteurs de bibliothèques
    • Il couvre les best practices lors de la construction au-dessus de Zod
    • Il répond aux questions fréquentes sur la prise en charge simultanée de Zod 3, Zod 4 et Mini

1 commentaires

 
GN⁺ 2025-05-20
Avis sur Hacker News
  • Je suis l’auteur, posez-moi vos questions. J’ai expliqué assez en détail les raisons de cette approche concernant la politique de versionnement : https://github.com/colinhacks/zod/issues/4371
    Au final, npm n’est pas conçu pour bien gérer la situation dans laquelle se trouve Zod. Des dizaines, voire des centaines de bibliothèques importent directement les interfaces/classes de Zod et les utilisent dans leur API publique ; à chaque montée de version majeure de Zod, ces bibliothèques doivent donc elles aussi publier une nouvelle version majeure
    Pris isolément, c’est raisonnable, mais avec Zod cela peut provoquer une avalanche de versions douloureuse pour tout le monde, et il semblait probable qu’une bonne partie de l’écosystème reste bloquée indéfiniment sur la v3
    Nous avons donc choisi une approche proche de celle de Go : au lieu de publier une nouvelle version du paquet introduisant une rupture de compatibilité, ajouter un nouveau sous-chemin. Dans l’écosystème TypeScript, une bibliothèque peut avoir une seule peer dependency zod@^3.25.0 et prendre ce dont elle a besoin depuis "zod/v3" et "zod/v4" afin de prendre en charge les deux versions en même temps

    • Les améliorations de performance de tsc dans les grands codebases sont particulièrement bienvenues, et les changements sur les unions discriminées devraient aussi beaucoup aider dans certains scénarios qui étaient jusqu’ici insuffisamment couverts
      Cela dit, même si je comprends pourquoi cette politique de versionnement un peu étrange a été choisie en raison de circonstances particulières, du point de vue d’une équipe qui n’a pas à se soucier des conflits de versions de Zod dans les dépendances transitives, j’aurais aimé qu’il existe aussi un paquet 4.0.0
      Si j’ai bien compris, il faut remplacer les imports par "zod/v4", ce qui est un changement très bruyant, et il peut être pénible de devoir attraper via une règle de lint les imports automatiques de l’IDE depuis 'zod'
    • Cette approche est très raisonnable. Cela signifie aussi que les mises à jour de sécurité des versions précédentes peuvent être fournies dans la même release du codebase
    • Je suis sur mobile, donc je n’ai pas vu si c’est déjà dans l’article, mais je me demande si la correction de .optional() dans TypeScript fait partie des 9 ou 10 principaux tickets résolus : https://github.com/colinhacks/zod/issues/635
      C’était mon plus gros point de friction avec Zod, mais Zod est tellement bon que je fais avec malgré tout
    • Grâce aux nouvelles fonctionnalités, je pense pouvoir supprimer beaucoup de hacks temporaires que j’avais en local. J’utilise ma propre version de https://github.com/raflymln/zod-key-parser pour éviter les fautes de frappe dans les noms de formulaires, et j’ai été surpris que ce genre de fonctionnalité ne soit pas directement intégrée à la bibliothèque
      Je me demande si vous considérez que cela sort du périmètre de Zod, ou si vous n’avez simplement pas encore eu le temps de l’implémenter. La discussion associée est ici : https://github.com/colinhacks/zod/discussions/2134
    • Si cela signifie que la toute première version de Zod 4 est 3.25.0, ça me semble assez absurde
      J’utilise les versions alpha de Zod depuis plusieurs mois et je voulais simplement modifier package.json pour faire la mise à niveau, mais maintenant j’ai l’impression que je vais devoir fouiller tout l’historique git
      Je suis très reconnaissant pour ce projet, mais sur ce point précis, j’ai l’impression que ce retour d’expérience a été rendu inutilement difficile. Il aurait peut-être été possible de publier aussi une 4.x en parallèle de la 3.x
  • Le fait de « distribuer Zod 4 avec Zod 3 dans la release zod@3.25, afin de simplifier la migration, et de l’importer depuis le sous-chemin "/v4" » ressemble à un signe que la gestion des dépendances npm est complètement bancale
    Les peer dependencies sont tellement cassées que la v4 doit faire semblant d’être la v3

    • Je suis l’auteur. J’ai expliqué assez en détail les raisons de cette approche ici : https://github.com/colinhacks/zod/issues/4371
      Il est vrai que npm ne gère pas bien la situation dans laquelle se trouve Zod. Cela dit, Zod a pour contrainte de ne quasiment dépendre d’aucune autre bibliothèque. Des dizaines, voire des centaines de bibliothèques importent directement des interfaces/classes depuis "zod" et les utilisent dans leur API publique
      Ces bibliothèques doivent publier une nouvelle version majeure à chaque montée de version majeure de Zod, et dans le cas de Zod cela peut provoquer une avalanche de versions douloureuse pour tout le monde. Honnêtement, il semblait probable qu’une bonne partie de l’écosystème reste bloquée indéfiniment sur la v3
      Nous avons donc choisi une approche similaire à Go : au lieu de publier une nouvelle version du paquet à chaque release avec rupture de compatibilité, ajouter un nouveau sous-chemin. Dans l’écosystème TypeScript, une seule peer dependency zod@^3.25.0 permet de prendre en charge simultanément "zod/v3" et "zod/v4"
    • La conclusion selon laquelle « les peer dependencies sont cassées, donc la v4 fait semblant d’être la v3 » ne me semble pas correcte. À mon avis, si Zod v4 est inclus dans la v3, c’est pour permettre aux utilisateurs de migrer progressivement
      Autrement dit, refactoriser les usages un par un vers import ... from 'zod/v4', puis, une fois terminé, passer entièrement à la v4
    • J’ai l’impression que n’importe quel propos négatif se fait recommander. Cette décision relève moins d’une limite intrinsèque de npm que d’une approche pragmatique permettant de faire évoluer progressivement des bibliothèques avec beaucoup de changements incompatibles
    • Peut-être que des années à n’utiliser que npm ont rétréci mon horizon, mais je me demande quelle serait une meilleure méthode pour effectuer une migration itérative de v3 vers v4 sans tout basculer d’un seul coup
    • Ce n’est pas un problème propre à npm. Le fait qu’une dépendance dépende elle-même, via une dépendance transitive, d’une ancienne version existe en réalité dans quasiment tous les écosystèmes
      Au contraire, npm offre davantage de portes de sortie, puisqu’il permet, si nécessaire, d’exécuter plusieurs versions en parallèle ou d’écraser sélectivement une partie du graphe des dépendances transitives
      Quel système de gestion de paquets résout ce problème ? Même des plateformes « stables » comme Maven traitent ce genre de situation en publiant les versions sous de nouveaux namespaces, comme lorsque Apache Commons est passé de v2 à v3
  • Il y a une question que je me pose depuis longtemps. J’ai entendu dire que Zod pouvait convenir à ce cas, mais même en lisant la documentation, je ne vois pas bien comment faire.
    Imaginons que l’API serveur renvoie des types plus précis que ce qu’elle peut exprimer. Par exemple, api/:postid/author renvoie un User, mais il peut s’agir d’un User normal ou d’un User anonyme, si bien que des champs comme username ou location peuvent arriver à null. Dans ce cas, on peut vouloir représenter l’objet User comme une union discriminée.
    Les objets provenant d’autres endpoints peuvent aussi nécessiter une conversion de type. Un User peut parfois inclure des Post[], et si un Post est un message de modérateur, il peut aussi avoir des propriétés spéciales.
    Avant, j’écrivais des fonctions comme normalizeUser() et normalizePost(), mais c’est vite devenu brouillon. Comme chaque endpoint renvoyait un sous-ensemble différent des modèles User/Post, je me suis retrouvé avec environ cinq normalizePost, et c’était beaucoup trop désordonné. Je me demande comment on résout généralement ce genre de problème.

    • Il semble qu’une union discriminée ferait l’affaire.
      On sépare par exemple les objets success et failed à partir d’un champ discriminant comme status. S’il y a beaucoup de propriétés spéciales pour les modérateurs, mais qu’on ne veut pas toutes les énumérer ni les vérifier, on peut définir un comportement de passage.
      Même si plusieurs méthodes ont des schémas différents, s’il existe une partie commune, on peut créer un schéma d’objet partagé, puis construire des objets qui y ajoutent des champs supplémentaires. S’il y a beaucoup de possibilités, cela restera désordonné, mais si la situation est déjà désordonnée, un validateur peut au moins valider ce désordre.
    • Idéalement, il faudrait une source unique de vérité sur les formes que peut prendre User. Cela peut être une union discriminée du type User et AnonymousUser.
      Si ce n’est pas du TypeScript full stack, par exemple avec un backend Python, on peut définir les différentes formes de User avec des modèles Pydantic et des unions, puis générer un schéma OpenAPI/GraphQL et produire les types du client TypeScript par génération de code.
    • Il faudrait en savoir plus sur le cas d’usage pour le résoudre, mais ajouter une propriété discriminante comme "user_type" à tous les types de l’union facilite la gestion des cas généraux et particuliers.
      Par exemple, si l’on vérifie user.user_type === 'authenticated', le système de types sait ensuite que user.name peut être utilisé.
    • Cela n’aide pas directement dans ce cas précis, mais GraphQL a été créé pour ce genre de chose.
      Les bibliothèques TypeScript pour requêtes GraphQL peuvent inférer dynamiquement la forme de la réponse à partir des champs sélectionnés. Si l’on sélectionne { user { username posts { text } } }, le type de réponse inclut posts; si l’on ne sélectionne que { user { username } }, la propriété posts disparaît complètement.
    • Le serveur doit exposer les types. Écrire les types à la main côté client n’a aucun sens.
      Le serveur sait quelles données il envoie, il doit donc fournir cette information au client sous forme de métadonnées. En pratique, cela peut vouloir dire qu’un backend Python utilise des schémas Pydantic, génère automatiquement une spécification OpenAPI à partir de ceux-ci, puis que le client génère ses types.
  • Zod est nettement meilleur que les alternatives que j’ai vues, mais le fait même d’avoir besoin de cette validation explicite ressemble parfois à un échec de l’endroit où en est arrivé le développement web moderne.
    En développement full stack, c’est très frustrant de devoir décrire la même forme de plusieurs manières. On finit par avoir besoin de validation des entrées en JS, de Swagger pour la définition d’API, de validation des entrées côté serveur, d’un ORM pour la conformité au schéma, et de définitions TypeScript séparées côté serveur et côté client, ce qui devient fastidieux.

    • Le fait que TypeScript s’obstine à être un système uniquement statique / de compilation est une blessure regrettable pour tout l’écosystème. Je ne veux pas que TypeScript devienne un vérificateur à l’exécution, mais j’aimerais qu’il expose des données de type utilisables de façon utile pour les classes, fonctions et objets.
      TypeScript donne l’impression d’être la meilleure source unique de vérité dont nous disposions, mais en réalité les outils qui tentent de faire de la réflexion redéfinissent chacun leur propre modèle et leur propre builder. Il existe à lui seul cinq grands domaines où la réflexion est centrale, chacun avec plusieurs implémentations.
      L’ancien outil d’émission de types TypeScript reflect-metadata fournit une partie des informations de type à l’exécution, mais il cible de très anciennes spécifications de décorateurs et de métadonnées : https://www.npmjs.com/package/reflect-metadata
      Peut-être en sommes-nous au tout début d’une unification. Le projet Standard Schema semble pris en charge par la plupart des grandes bibliothèques de validation. Cela dit, l’étendre jusqu’aux outils de définition d’API ou aux ORM en est encore à un stade très précoce.
      https://github.com/standard-schema/standard-schema?tab=readm...
    • En fait, c’est le cœur de ce type d’outil. Il suffit de définir une seule fois, puis de générer dynamiquement tout ce qui est en dessous.
      Quand on modifie une fois le schéma Zod, cela se propage à toute l’application avec la vérification de types. Le schéma Zod devient en quelque sorte la source unique de vérité.
    • En général, il n’est pas nécessaire de redéfinir les données partout. Il existe énormément d’outils pour convertir vers Zod ou depuis Zod.
      Si l’on dispose déjà d’un schéma JSON Schema/Swagger, il suffit de générer Zod à partir de celui-ci. Si l’on utilise un ORM TypeScript, il y a presque certainement un générateur Zod.
      Franchement, Zod est tellement répandu qu’à mes yeux il devient une définition de schéma unifiée sur laquelle le reste de la stack peut s’appuyer. Comme les types sont définis directement, les développeurs les maintiennent réellement à jour. La documentation Swagger de mon entreprise est toujours en retard sur les changements.
    • Toutes les API sont expérimentales et en constante évolution, et le web aussi.
      Le statu quo ne convient que lorsqu’on a affaire à des clients et des employeurs qui veulent simplement le résultat et ne s’intéressent pas à la manière. Dans ce contexte, ces malheureuses couches de complexité augmentent au moins le temps facturable.
    • Beaucoup de gens qui se plaignent de la complexité du développement web moderne seraient probablement horrifiés par l’idée de tout remplacer simplement par TypeScript et Zod.
      En supposant bien sûr que Zod soit la bibliothèque de définition de schémas et de validation TypeScript qu’ils ont choisie.
  • Zod 4 a l’air prometteur, mais même avec les dernières améliorations, ArkType reste plusieurs fois plus rapide, et encore avec un facteur à un chiffre.
    Pour des raisons de rétrocompatibilité et de compatibilité syntaxique, il est parfois difficile de faire aussi rapide qu’une bibliothèque repartie complètement de zéro. J’ai analysé tous ces outils dans un projet récent et j’ai choisi ArkType en partie pour cette raison. L’expérience TypeScript m’a aussi semblé meilleure.

    • J’ai regardé les métriques de vitesse, mais je me demande si vous pouvez expliquer où cette vitesse fait la différence.
      Nous n’utilisons Zod que pour la validation de formulaires, donc je me dis : « pourquoi est-ce important ? ». Peut-être que des gens valident des choses comme des messages d’entrée d’API à haut débit, où les performances deviennent plus importantes.
    • Je suis curieux de savoir pourquoi vous avez choisi ArkType plutôt que TypeBox.
    • Fait intéressant, je n’avais même pas vu cet outil pendant mes recherches. Je regardais moi aussi surtout l’expérience TypeScript.
      Cela dit, je ne pense pas quitter Zod.
    • ArkType est un cauchemar à utiliser, Zod est agréable à utiliser.
  • Félicitations à l’équipe Zod pour cette nouvelle version. Même au risque de paraître trop négatif, le nombre de changements cassant la compatibilité indiqués dans le guide de migration me donne des frissons.
    Pour un projet qui dépend fortement de Zod, cela ressemble à une tâche intimidante qui demandera beaucoup de concentration et de temps aux développeurs. Cela me parle particulièrement, ayant maintenu au travail plusieurs projets frontend âgés de 4 à 5 ans.
    Les gros projets React dépendent généralement de nombreuses bibliothèques, et quand chacune publie de gros changements, surtout avec une documentation insuffisante, on est vite submergé. C’est l’un des aspects que je déteste le plus dans le travail avec JavaScript : garder tout aligné et continuer à faire tourner l’ensemble sans heurts donne l’impression d’une montée interminable.

    • Entièrement d’accord. Nous exploitons quelques grosses apps Next.js et, au cours de l’année écoulée, nous avons dû encaisser les gros changements de cache de Next.js 14 → 15, la migration de Next.js pages vers l’app router, React 18 → 19, Eslint 8 → 9, et Tailwind 3 → 4.
      Franchement, ça a été un cauchemar, et je me suis dit que j’aurais préféré que ce soit fait avec Django. Contrairement à ce que j’attendais, la migration Tailwind 3 → 4 a été parmi les plus douloureuses.
    • C’est pour cela qu’ils ont opté pour une double distribution avec une édition mini séparée. Cela facilite une migration progressive sans toucher au gestionnaire de paquets.
      Les utilisateurs qui ne s’intéressent pas à l’édition mini n’ont pas besoin de s’en préoccuper. Mais les avantages de tree shaking de l’édition mini étaient si importants qu’ils encourageaient le développement d’alternatives, et Zod devait soit les adopter, soit décliner.
    • Il suffit d’utiliser un LLM.
  • En tant que développeur full-stack exploitant moi-même un SaaS en production avec des milliers d’utilisateurs, je suis parfois agréablement surpris de constater combien de problèmes m’échappent totalement parce que j’ai choisi de ne pas faire de SPA et de ne pas utiliser de framework frontend JS.
    Je n’ai même jamais pensé avoir besoin de choses comme Zod/ArkType, je n’en avais jamais entendu parler, et je n’en aurai pas l’usage.
    Je suis étonné par la quantité d’efforts, de complexité et d’outils nécessaires pour créer une SPA. Quand on décide de ne pas créer de SPA, toute une catégorie de problèmes cesse tout simplement d’exister. À la place, on utilise le navigateur comme il a été conçu à l’origine, avec des rechargements complets de page et un développement centré sur le backend, en ajoutant parfois de la réactivité avec un framework exclusivement backend comme Laravel Livewire.
    Tout est plus simple, du contrôle d’accès à la validation en passant par la gestion d’état. L’app est rapide, responsive, moderne, SEO-friendly, et sert des milliers d’utilisateurs en production.

    • Sur deux gros projets réunissant plus de 5 équipes, nous avons utilisé Zod et Protobuf pour permettre une bonne évolution des schémas. Même avec un frontend léger, il est pertinent d’utiliser quelque chose qui valide les schémas côté backend.
      Au bout du compte, il y a bien un schéma quelque part. Il peut être défini dans le système de base de données ou dans les modèles de l’ORM. Mais dans de gros projets, placer le schéma dans le système de base de données ou l’ORM peut créer des problèmes très difficiles, donc nous utilisons Zod et Protobuf. À mon avis, Protobuf pourrait aussi être entièrement remplacé par Zod ou quelque chose de similaire.
      Le scandale du Post Office britannique implique un système informatique appelé Horizon : https://en.wikipedia.org/wiki/British_Post_Office_scandal
      En lisant les détails, j’ai l’impression qu’une validation de schéma comme Zod aurait pu contribuer à empêcher ce scandale. L’annexe technique des documents judiciaires du recours collectif mentionne aussi l’absence d’utilisation de schémas : https://en.wikipedia.org/wiki/Bates_%26_Others_v_Post_Office...
    • Zod n’a rien à voir avec les SPA et ce n’est pas non plus un outil uniquement frontend. Vous ne faites pas de validation des entrées dans votre code ?
    • Quand on ferme les yeux, il arrive aussi que toute une catégorie de problèmes cesse d’exister.
    • Je suis curieux de savoir comment vous faites la validation côté serveur.
      Pour l’instant, on dirait que vous écrivez défensivement une tonne de if. Pire encore, vous vous reposez peut-être uniquement sur la validation de formulaires HTML côté client.
    • Nous avons énormément de schémas Zod uniquement backend, utilisés dans une partie de nos pipelines de données. Donc ça ne ressemble pas à un outil qui existerait seulement pour résoudre des problèmes de SPA.
  • Je ne suis pas expert, donc je reste prudent, mais je me disais que JSON Schema, étant fondé sur des schémas, pouvait être un bon choix puisqu’il permet d’implémenter des validateurs dans des langages autres que TypeScript
    https://ajv.js.org est l’une de ces bibliothèques JSON Schema. Je me demande comment elle se compare à Zod

    • Zod n’est pas un outil destiné uniquement à la validation JSON. Il peut valider des objets qui ne peuvent pas être représentés en JSON sans transformation, par exemple des dates ou des instances de classes
      Si on le souhaite, il peut aussi servir de convertisseur JSON. Par exemple, on peut écrire un schéma qui reçoit une chaîne, vérifie qu’il s’agit d’une chaîne de date ISO et produit un objet Date
    • Zod 4 prend en charge nativement la conversion des schémas Zod en JSON Schema. C’était déjà possible auparavant via des bibliothèques tierces
      La différence importante concerne le prétraitement et refine. Dans Zod, on peut fournir un callback avant la validation, ce qui est très utile mais impossible à représenter en JSON. Par exemple, transformer MM/DD/YYYY en DD/MM/YYYY avant la validation d’une date s’avère plus souvent utile qu’on ne le pense
    • Dans ce genre de cas, JSON Schema est un bon choix, et TypeBox est une bonne manière d’en générer
      Pour la validation, on peut utiliser AJV ou le système de validation de schémas propre à TypeBox. Ce dernier est beaucoup plus rapide, mais ne prend en charge que le synchrone, tandis qu’AJV propose des options de validation asynchrone, comme des vérifications en base de données
    • Pour la validation entre langages, JSON Schema est le bon choix. En l’enveloppant avec OpenAPI, on obtient aussi gratuitement une documentation d’API correcte
  • Les réactions négatives autour de ce sujet me surprennent
    J’ai testé une première version de Zod v4 et j’ai apprécié la nouvelle API, mais j’étais très inquiet de ce à quoi ressemblerait le chemin de migration. J’envisageais même de proposer de la publier sous un tout nouveau nom de package
    Mais l’approche de l’auteur est intelligente. Elle permet à des personnes comme moi d’adopter v4 immédiatement, sans attendre que toutes les dépendances soient mises à jour

    • C’est une bonne voie. Pour quelque chose comme la validation, il n’y a aucun moyen de gérer une migration du type tout ou rien
  • Je venais tout juste de commencer à adopter Zod dans un nouveau projet, et le moment ne pouvait pas être mieux choisi
    D’après ce que je vois maintenant, il aurait vraiment fallu changer beaucoup de choses pour passer à v4