Comment j'ai essayé d'améliorer le mocking avec Zod
Si vous êtes un ingénieur front-end, vous avez probablement été dans une situation où vous avez dû commencer à implémenter une fonctionnalité avant l'API qui sert la partie back-end de celle-ci. fonctionnalité existe. Les ingénieurs se tournent souvent vers la simulation pour permettre le développement parallèle (ce qui signifie que les parties front-end et back-end de la fonctionnalité sont développées en parallèle).
Les moqueries peuvent cependant présenter certains inconvénients. La première et la plus évidente est que les simulations peuvent s’écarter de la mise en œuvre réelle, ce qui les rend peu fiables. Un deuxième problème est que les moqueries peuvent souvent être verbeuses ; Avec les simulations qui contiennent beaucoup de données, il peut être difficile de savoir de quoi se moque réellement une certaine réponse simulée.
Les données ci-dessous sont un exemple de certaines données que vous pourriez trouver dans une base de code :
type Order = { orderId: string; customerInfo: CustomerInfo; // omitted these types for brevity orderDate: string; items: OrderItem[]; paymentInfo: PaymentInfo; subtotal: number; shippingCost: number; tax: number; totalAmount: number; status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled'; trackingNumber: string | null; }; const mockOrders: Order[] = [ { orderId: "ORD-2024-001", customerInfo: { id: "CUST-1234", name: "Alice Johnson", email: "alice.j@email.com", shippingAddress: { street: "123 Pine Street", city: "Portland", state: "OR", zipCode: "97201", country: "USA" } }, orderDate: "2024-03-15T14:30:00Z", items: [ { productId: "PROD-789", name: "Organic Cotton T-Shirt", quantity: 2, pricePerUnit: 29.99, color: "Navy", size: "M" }, { productId: "PROD-456", name: "Recycled Canvas Tote", quantity: 1, pricePerUnit: 35.00, color: "Natural" } ], paymentInfo: { method: "credit_card", status: "completed", transactionId: "TXN-88776655" }, subtotal: 94.98, shippingCost: 5.99, tax: 9.50, totalAmount: 110.47, status: "shipped", trackingNumber: "1Z999AA1234567890" }, // Imagine more objects here, with various values changed... ];
Les données avec lesquelles je travaille quotidiennement ressemblent beaucoup à ceci. Des tableaux de commandes ou une sorte d'informations axées sur le client, comportant des valeurs imbriquées qui aident à remplir des tableaux, des fenêtres contextuelles et des cartes détaillées avec toutes sortes d'informations.
En tant qu'ingénieur chargé de maintenir des applications qui s'appuient fortement sur de telles simulations, vous pourriez vous demander « quel est cet objet particulier dans la réponse moqueuse ? ». Je me suis souvent retrouvé à parcourir des centaines d'exemples comme celui ci-dessus, sans être sûr du but de chaque objet.
Au fur et à mesure que je suis devenu plus sûr de moi en tant qu'ingénieur, je me suis chargé de résoudre le problème ci-dessus ; Et si chaque maquette pouvait afficher plus facilement son objectif ? Et si un ingénieur n’avait qu’à écrire les lignes dont il a l’intention de se moquer ?
En jouant avec du code et une bibliothèque appelée Zod, j'ai trouvé la méthode suivante appelée parse, qui tente de valider les données entrantes par rapport à un type connu :
const stringSchema = z.string(); stringSchema.parse("fish"); // => returns "fish" stringSchema.parse(12); // throws error
C'était un moment d'éclairage ; Ce petit exemple dans la documentation de Zod était exactement ce que je cherchais ! Si la méthode d'analyse pouvait accepter une valeur et la renvoyer, alors si je transmettais une valeur, je la récupérerais. Je savais aussi déjà que je pouvais définir des valeurs par défaut pour un schéma Zod. Et si passer un objet vide renvoyait un objet plein, avec ses valeurs ? Et voilà, c’est le cas ; Je pourrais définir des valeurs par défaut sur un schéma Zod et renvoyer les valeurs par défaut :
const UserSchema = z.object({ id: z.string().default('1'), name: z.string().default('Craig R Broughton'), settings: z.object({ theme: z.enum(['light', 'dark']), notifications: z.boolean() }).default({ theme: 'dark', notifications: true, }) }); const user = UserSchema.parse({}) // returns a full user object
Maintenant, j'avais un moyen de générer des objets, mais ce n'était toujours pas tout à fait ce que je cherchais. Ce que je voulais vraiment, c'était un moyen de seulement écrire les lignes exactes dont je me « moquais ». Une solution simple pourrait ressembler à :
const UserSchema = z.object({ id: z.string().default('1'), name: z.string().default('Craig R Broughton'), settings: z.object({ theme: z.enum(['light', 'dark']), notifications: z.boolean() }).default({ theme: 'dark', notifications: true, }) }); const user = UserSchema.parse({}) const overridenUser = {...user, ...{ name: "My new name", settings: {}, // I would need to write every key:value for settings :( } satisfies Partial<z.infer<typeof UserSchema>>} // overrides the base object
Cependant, cela a ses propres défauts ; Que se passe-t-il si la valeur que je souhaite remplacer est elle-même un objet ou un tableau ? Je devrais alors taper manuellement chaque ligne qui était auparavant requise pour que cette fonctionnalité continue de fonctionner et soit moquée comme prévu, ce qui va à l'encontre de l'objectif de notre solution de travail en cours.
Pendant longtemps, c'est tout ce que j'en étais, jusqu'à très récemment, lorsque j'ai eu une autre tentative d'améliorer ce qui précède. La première étape consistait à définir « l'API » ; Comment voulais-je que mes utilisateurs interagissent avec cette fonctionnalité ?
type Order = { orderId: string; customerInfo: CustomerInfo; // omitted these types for brevity orderDate: string; items: OrderItem[]; paymentInfo: PaymentInfo; subtotal: number; shippingCost: number; tax: number; totalAmount: number; status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled'; trackingNumber: string | null; }; const mockOrders: Order[] = [ { orderId: "ORD-2024-001", customerInfo: { id: "CUST-1234", name: "Alice Johnson", email: "alice.j@email.com", shippingAddress: { street: "123 Pine Street", city: "Portland", state: "OR", zipCode: "97201", country: "USA" } }, orderDate: "2024-03-15T14:30:00Z", items: [ { productId: "PROD-789", name: "Organic Cotton T-Shirt", quantity: 2, pricePerUnit: 29.99, color: "Navy", size: "M" }, { productId: "PROD-456", name: "Recycled Canvas Tote", quantity: 1, pricePerUnit: 35.00, color: "Natural" } ], paymentInfo: { method: "credit_card", status: "completed", transactionId: "TXN-88776655" }, subtotal: 94.98, shippingCost: 5.99, tax: 9.50, totalAmount: 110.47, status: "shipped", trackingNumber: "1Z999AA1234567890" }, // Imagine more objects here, with various values changed... ];
L'API ci-dessus permettrait à l'utilisateur de spécifier un schéma de son choix, puis de fournir les remplacements appropriés et de renvoyer un objet utilisateur ! Bien sûr, nous voudrions tenir compte correctement des tableaux ainsi que d'un seul objet. À cette fin, une simple vérification de type par rapport au type de remplacement entrant s'est avérée suffisante :
const stringSchema = z.string(); stringSchema.parse("fish"); // => returns "fish" stringSchema.parse(12); // throws error
Ce qui précède est effectivement le même code qu'avant, mais il encapsule désormais l'analyse en interne afin que les utilisateurs n'aient pas à le faire manuellement ou à connaître des informations détaillées sur la méthode d'analyse de Zods. Comme vous l'avez peut-être deviné en lisant l'instruction if/else incluse, nous avons également résolu la préservation des objets et des tableaux imbriqués grâce à l'utilisation d'une fonction de création récursive qui analyse chaque valeur et renvoie ses valeurs par défaut spécifiées dans le schéma Zod.
Ce qui précède est assez compliqué à comprendre, mais le résultat est qu'un utilisateur peut faire ce qui suit :
const UserSchema = z.object({ id: z.string().default('1'), name: z.string().default('Craig R Broughton'), settings: z.object({ theme: z.enum(['light', 'dark']), notifications: z.boolean() }).default({ theme: 'dark', notifications: true, }) }); const user = UserSchema.parse({}) // returns a full user object
En fournissant l'option de configuration verifyNestedDefaults au constructeur, un utilisateur peut conserver les paires clé-valeur dans un objet ou un tableau imbriqué ! Cela résout le problème d'un utilisateur remplaçant une clé qui n'est pas un type primitif comme une chaîne, mais plutôt un type plus complexe et conserve toutes les valeurs moins celles que nous choisissons de remplacer.
Cela a déjà été une sacrée lecture, alors terminons par le résultat de tout notre travail acharné. Revenons sur cette première simulation et comment nous pourrions l'écrire avec zodObjectBuilder. Définissons d’abord nos types et nos valeurs par défaut, et passons le schéma résultant dans le zodObjectBuilder :
const UserSchema = z.object({ id: z.string().default('1'), name: z.string().default('Craig R Broughton'), settings: z.object({ theme: z.enum(['light', 'dark']), notifications: z.boolean() }).default({ theme: 'dark', notifications: true, }) }); const user = UserSchema.parse({}) const overridenUser = {...user, ...{ name: "My new name", settings: {}, // I would need to write every key:value for settings :( } satisfies Partial<z.infer<typeof UserSchema>>} // overrides the base object
L'implémentation ci-dessus renverra un seul objet en utilisant toutes les valeurs par défaut ! Mais nous pouvons faire mieux que cela, nous pouvons maintenant (avec l'aide de quelques définitions de surcharge et d'une analyse interne) créer des tableaux d'objets, parfaits pour le cas d'utilisation des réponses API moqueuses :
const UserSchema = z.object({ id: z.string().default('1'), name: z.string().default('Craig R Broughton'), settings: z.object({ theme: z.enum(['light', 'dark']), notifications: z.boolean() }).default({ theme: 'dark', notifications: true, }) }); const user = zodObjectBuilder({ schema: UserSchema, overrides: { name: 'My new name', settings: { theme: 'dark' } } // setting is missing the notifications theme :( }); // returns a full user object with the overrides
Ce qui précède génère un tableau de commandes avec les valeurs par défaut complètes, avec des statuts de livraison remplacés ! Espérons que cela démontre comment la fonction zodObjectBuilder peut minimiser l'effort requis pour créer une nouvelle simulation basée sur un schéma de type sécurisé fiable.
Avec cette petite démonstration, nous avons atteint la fin de mon premier article :) J'espère que vous avez apprécié la lecture de ce voyage d'exploration pour améliorer la moquerie. zodObjectBuilder est toujours en cours de construction, mais il répond bien à mes besoins pour minimiser les objets simulés. Si vous souhaitez jouer avec la version actuelle, vous pouvez la trouver sur https://www.npmjs.com/package/@crbroughton/ts-utils qui inclut la fonction.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds











Python convient plus aux débutants, avec une courbe d'apprentissage en douceur et une syntaxe concise; JavaScript convient au développement frontal, avec une courbe d'apprentissage abrupte et une syntaxe flexible. 1. La syntaxe Python est intuitive et adaptée à la science des données et au développement back-end. 2. JavaScript est flexible et largement utilisé dans la programmation frontale et côté serveur.

Le passage de C / C à JavaScript nécessite de s'adapter à la frappe dynamique, à la collecte des ordures et à la programmation asynchrone. 1) C / C est un langage dactylographié statiquement qui nécessite une gestion manuelle de la mémoire, tandis que JavaScript est dynamiquement typé et que la collecte des déchets est automatiquement traitée. 2) C / C doit être compilé en code machine, tandis que JavaScript est une langue interprétée. 3) JavaScript introduit des concepts tels que les fermetures, les chaînes de prototypes et la promesse, ce qui améliore la flexibilité et les capacités de programmation asynchrones.

Les principales utilisations de JavaScript dans le développement Web incluent l'interaction client, la vérification du formulaire et la communication asynchrone. 1) Mise à jour du contenu dynamique et interaction utilisateur via les opérations DOM; 2) La vérification du client est effectuée avant que l'utilisateur ne soumette les données pour améliorer l'expérience utilisateur; 3) La communication de rafraîchissement avec le serveur est réalisée via la technologie AJAX.

L'application de JavaScript dans le monde réel comprend un développement frontal et back-end. 1) Afficher les applications frontales en créant une application de liste TODO, impliquant les opérations DOM et le traitement des événements. 2) Construisez RestulAPI via Node.js et Express pour démontrer les applications back-end.

Comprendre le fonctionnement du moteur JavaScript en interne est important pour les développeurs car il aide à écrire du code plus efficace et à comprendre les goulots d'étranglement des performances et les stratégies d'optimisation. 1) Le flux de travail du moteur comprend trois étapes: analyse, compilation et exécution; 2) Pendant le processus d'exécution, le moteur effectuera une optimisation dynamique, comme le cache en ligne et les classes cachées; 3) Les meilleures pratiques comprennent l'évitement des variables globales, l'optimisation des boucles, l'utilisation de const et de locations et d'éviter une utilisation excessive des fermetures.

Python et JavaScript ont leurs propres avantages et inconvénients en termes de communauté, de bibliothèques et de ressources. 1) La communauté Python est amicale et adaptée aux débutants, mais les ressources de développement frontal ne sont pas aussi riches que JavaScript. 2) Python est puissant dans les bibliothèques de science des données et d'apprentissage automatique, tandis que JavaScript est meilleur dans les bibliothèques et les cadres de développement frontaux. 3) Les deux ont des ressources d'apprentissage riches, mais Python convient pour commencer par des documents officiels, tandis que JavaScript est meilleur avec MDNWEBDOCS. Le choix doit être basé sur les besoins du projet et les intérêts personnels.

Les choix de Python et JavaScript dans les environnements de développement sont importants. 1) L'environnement de développement de Python comprend Pycharm, Jupyternotebook et Anaconda, qui conviennent à la science des données et au prototypage rapide. 2) L'environnement de développement de JavaScript comprend Node.js, VScode et WebPack, qui conviennent au développement frontal et back-end. Le choix des bons outils en fonction des besoins du projet peut améliorer l'efficacité du développement et le taux de réussite du projet.

C et C jouent un rôle essentiel dans le moteur JavaScript, principalement utilisé pour implémenter des interprètes et des compilateurs JIT. 1) C est utilisé pour analyser le code source JavaScript et générer une arborescence de syntaxe abstraite. 2) C est responsable de la génération et de l'exécution de bytecode. 3) C met en œuvre le compilateur JIT, optimise et compile le code de point chaud à l'exécution et améliore considérablement l'efficacité d'exécution de JavaScript.
