<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>@VinceOPS | Blog d'un passionné Blog</title>
        <link>https://vinceops.me/</link>
        <description>@VinceOPS | Blog d'un passionné Blog</description>
        <lastBuildDate>Sat, 12 Dec 2020 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>fr</language>
        <item>
            <title><![CDATA[Télétravail : Mon bureau "home made"]]></title>
            <link>https://vinceops.me/remote-bureau-diy</link>
            <guid>https://vinceops.me/remote-bureau-diy</guid>
            <pubDate>Sat, 12 Dec 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Ces dernières semaines, j'ai vu passer plusieurs vidéos de Youtubeurs (dévs & gamers) présentant leur setup et certains m'ont bluffé ! Puisque je reprends le télétravail à temps complet avec mon nouveau job, j'ai décidé de me fabriquer un bureau digne de ce nom, en piquant quelques bonnes idées. L'objectif étant de gagner avant tout en confort, puisque j'utilisais depuis quelques semaines une console de 45cm de profondeur 😅.]]></description>
            <content:encoded><![CDATA[<p>Ces dernières semaines, j'ai vu passer plusieurs vidéos de Youtubeurs (dévs &amp; <em>gamers</em>) présentant leur <em>setup</em> et certains m'ont bluffé ! Puisque je reprends le télétravail à temps complet avec mon nouveau job, j'ai décidé de me fabriquer un bureau digne de ce nom, en piquant quelques bonnes idées. L'objectif étant de gagner avant tout en confort, puisque j'utilisais depuis quelques semaines une console de 45cm de profondeur 😅.</p>
<p>Dans cet article un peu inhabituel car <strong>non technique</strong>, je résume les étapes de création de mon modeste "nouveau" <em>setup</em>.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="le-matériel">Le matériel<a href="https://vinceops.me/remote-bureau-diy#le-mat%C3%A9riel" class="hash-link" aria-label="Lien direct vers Le matériel" title="Lien direct vers Le matériel">​</a></h2>
<p><em>Aucun sponsoring, ni placement de produit. La plupart des fournitures peuvent être achetées dans des enseignes physiques... Mais c'est plus compliqué en plein confinement.</em></p>
<p>Avant de me lancer, j'ai évidemment fait le point sur les contraintes esthétiques et budgétaires ainsi que sur l'espace disponible. Mais aussi sur le temps que je voulais et pouvais y accorder. Le bricolage, comme le développement, a ce goût facheux de "on peut toujours faire mieux" et "oups, ça fait déjà X heures que j'y suis".</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="plan-ou-plateau-ou-tablette">Plan, ou plateau, ou tablette<a href="https://vinceops.me/remote-bureau-diy#plan-ou-plateau-ou-tablette" class="hash-link" aria-label="Lien direct vers Plan, ou plateau, ou tablette" title="Lien direct vers Plan, ou plateau, ou tablette">​</a></h3>
<p>Je le voulais épais et en bois brut, profond d'au moins 60 cm et long de 140 cm. J'ai trouvé chez Leroy Merlin des plans de travail en chêne <a href="https://fr.wikipedia.org/wiki/Bois_lamell%C3%A9-coll%C3%A9" target="_blank" rel="noopener noreferrer">lamellé collé</a> de 250 x 65 x 3.6 cm, <a href="https://www.leroymerlin.fr/v3/p/produits/plan-de-travail-bois-chene-lamelle-brut-l-250-x-p-65-cm-ep-36-mm-e1501080820" target="_blank" rel="noopener noreferrer">pour 149.5€</a>. J'ai payé 5€ (en magasin) pour une coupe à 140 cm. J'ai déjà prévu de faire un banc avec la chute de 110 cm, mais ça, c'est totalement hors-sujet 😂.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="bois-avant-apres" src="https://vinceops.me/assets/images/bois-avant-apres-b9ec618292efce3fd3611e1a4c997a12.jpg" width="600" height="382" class="img_BhpN"><br>
<em>La coupe de 140 cm vernie (derrière) et sa chute</em></p></div>
<p>J'ai aussi acheté du vernis pour embellir la teinte du bois et le protéger des liquides (<em>coffee &amp; tea snob speaking 🤓</em>). Un vernis mat couleur chêne clair à <a href="https://www.leroymerlin.fr/v3/p/produits/vernis-meuble-et-objet-v33-chene-clair-mat-0-25l-e1400037775" target="_blank" rel="noopener noreferrer">11.90€</a>. J'avais déjà le pinceau (premier prix).</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="vernis" src="https://vinceops.me/assets/images/vernis-e8cd9326f5752376d8e6989565d4614c.jpg" width="650" height="442" class="img_BhpN"></p></div>
<p><strong>Coût</strong> : ~ 167€ (avec une chute de 110 cm).</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p><strong>Minute menuiserie</strong> : j'ai lu plusieurs recommandations d'utiliser des produits Rubio plutôt que du vernis : n'ayant pas pu essayé, je n'ai pas d'avis. Mais ils sont bien plus chers et je n'avais pas envie d'attendre la livraison !</p></div></div>
<p>Enfin, il faut poncer ce plateau ! J'avais déjà la ponceuse, les feuilles abrasives (grain 120 et 240) et les tréteaux. Les tréteaux sont optionnels mais il faut absolument une cale à poncer (à défaut d'une ponceuse) et des feuilles abrasives.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="les-pieds">Les pieds<a href="https://vinceops.me/remote-bureau-diy#les-pieds" class="hash-link" aria-label="Lien direct vers Les pieds" title="Lien direct vers Les pieds">​</a></h3>
<p>Je savais précisément ce que je voulais : des cadres en acier d'au moins 70 cm de haut et de 50 cm de profondeur. C'est sur Amazon que j'ai trouvé le meilleur prix. <a href="https://www.amazon.fr/gp/product/B07NQLG9M6" target="_blank" rel="noopener noreferrer">Ce modèle</a> de 72 x 50 x 6 cm, pour 94€ (84€ de pieds, 10€ de livraison).</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Pied cadre en acier" src="https://vinceops.me/assets/images/pied-40d91ebd21de85b97d307b752f8dcb36.jpg" width="500" height="485" class="img_BhpN"></p></div>
<p>Pour l'assemblage, j'ai acheté des vis <a href="https://www.leroymerlin.fr/v3/p/quincaillerie-en-vrac-en-libre-service-l1401590326" target="_blank" rel="noopener noreferrer">au poids</a> chez Leroy Merlin, de 6 mm de diamètre (le plus épais à la vente, avant de passer aux tire-fonds) et de 30 mm de long, la planche faisant 36 mm d'épaisseur. Coût négligeable : moins de 2€.</p>
<p><strong>Coût</strong> : ~ 96€.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="au-travail">Au travail<a href="https://vinceops.me/remote-bureau-diy#au-travail" class="hash-link" aria-label="Lien direct vers Au travail" title="Lien direct vers Au travail">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="assemblage">Assemblage<a href="https://vinceops.me/remote-bureau-diy#assemblage" class="hash-link" aria-label="Lien direct vers Assemblage" title="Lien direct vers Assemblage">​</a></h3>
<p>J'ai pu préparer le plateau en attendant les pieds. Les étapes sont relativement simples :</p>
<ul>
<li>Ponçage (grain 120), un coup d'aspirateur et on essuie au chiffon humide.</li>
<li>Première couche de vernis (au pinceau) que je laisse sécher 2 heures.</li>
<li>Ponçage très léger (grain 240) pour enlever les aspérités ("égrener"), un coup d'aspirateur et on essuie au chiffon humide.</li>
<li>Deuxième et dernière couche de vernis (toujours au pinceau), que je laisse sécher 24 heures.</li>
<li>Ponçage superficiel (grain 240) pour obtenir une surface lisse... Et on nettoie encore.</li>
</ul>
<p>J'ai regardé quelle face avait le meilleur aspect, pour en faire le dessus du bureau. C'est naturellement dans l'autre face que j'ai vissé les pieds.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Assemblage" src="https://vinceops.me/assets/images/assemblage-pieds-4ac2559edaca1914dd7db6ba731050eb.jpg" width="500" height="667" class="img_BhpN"><br>
<em>Centrés sur la profondeur et écartés du bord de ~1/8ème de la largeur du plan</em></p></div>
<p>Et voici ce qu'on obtient pour 263€ (hors pinceau et ponceuse/papier de verre) :</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Basic desk" src="https://vinceops.me/assets/images/bureau-en-place-a834852feab7e3f2d0a81b3f8e530019.jpg" width="500" height="528" class="img_BhpN"></p></div>
<p>J'ai profité des étapes de ponçage pour arrondir les angles (<strong>border-radius</strong> quand tu nous tiens !) et rendre la pose des avant-bras plus confortables, en plus d'adoucir le rendu visuel du plan. À ce stade, j'avais déjà investi environ 4 heures dans le projet, en comptant l'aller-retour en magasin.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="pimp-my-desk">Pimp My Desk<a href="https://vinceops.me/remote-bureau-diy#pimp-my-desk" class="hash-link" aria-label="Lien direct vers Pimp My Desk" title="Lien direct vers Pimp My Desk">​</a></h3>
<p>C'est super, mais on est <a href="https://www.youtube.com/watch?v=aRgqQe-8zYk" target="_blank" rel="noopener noreferrer">encore loin</a> des bureaux de <a href="https://www.youtube.com/watch?v=QVEp781Welg" target="_blank" rel="noopener noreferrer">grands seigneurs</a> de Youtube. Certes, mais on peut toujours s'en approcher. Enfin, voilà où j'en suis actuellement :</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Pimped desk" src="https://vinceops.me/assets/images/final-desk-red-27ecfedfc6d8902b1b4d31aa5037dc53.jpg" width="650" height="426" class="img_BhpN"></p></div>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="un-piédestal-pour-leurs-majestés">Un piédestal pour leurs majestés<a href="https://vinceops.me/remote-bureau-diy#un-pi%C3%A9destal-pour-leurs-majest%C3%A9s" class="hash-link" aria-label="Lien direct vers Un piédestal pour leurs majestés" title="Lien direct vers Un piédestal pour leurs majestés">​</a></h4>
<p>J'aime travailler en dual screen, en utilisant mon laptop comme écran secondaire. Pour des raisons de confort (et faciliter son refroidissement), j'ai acheté un support dédié à <a href="https://www.amazon.fr/gp/product/B07T4K1SXX" target="_blank" rel="noopener noreferrer">30€</a>, simple mais efficace, avec un design tout à fait valide pour ce prix.</p>
<p>Quant à moi, j'ai découvert récemment les joies du coussin repose-pieds et en ai acheté un pour <a href="https://www.amazon.fr/gp/product/B0855J8KR6" target="_blank" rel="noopener noreferrer">15€</a>.</p>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="couvrez-ce-câble-que-je-ne-saurais-voir">Couvrez ce câble que je ne saurais voir<a href="https://vinceops.me/remote-bureau-diy#couvrez-ce-c%C3%A2ble-que-je-ne-saurais-voir" class="hash-link" aria-label="Lien direct vers Couvrez ce câble que je ne saurais voir" title="Lien direct vers Couvrez ce câble que je ne saurais voir">​</a></h4>
<p>Le <em>cable management</em>, étape si chère à tant de perfectionnistes, joue un role clé dans le rendu final du <em>setup</em>. J'avais déjà des serre-câbles auto-bloquants, j'ai donc seulement acheté des clips adhésifs sur Amazon pour <a href="https://www.amazon.fr/gp/product/B07Z1JTZNP/" target="_blank" rel="noopener noreferrer">12€</a> et du ruban adhésif double-face pour <a href="https://www.amazon.fr/gp/product/B00EDLPG7Y" target="_blank" rel="noopener noreferrer">10€</a>.</p>
<p>La prise de courant la plus proche étant face au pied "arrière gauche", j'ai profité de celui-ci pour y cacher ma multiprise (collée au double-face). Dans la mesure où je n'ai pas opté pour des <a href="https://www.fully.com/standing-desks/jarvis.html" target="_blank" rel="noopener noreferrer">pieds réglables</a> (je n'aime pas bosser debout), le reste a été extrêmement simplifié par l'achat d'un bras-support pour mon écran (un vieux iiyama 24" qui prendra bientôt sa retraite) pour <a href="https://www.amazon.fr/gp/product/B01MZ70QJB" target="_blank" rel="noopener noreferrer">35€</a>, déjà équipé de de bagues passe-câbles.</p>
<p>J'ai suivi deux règles :</p>
<ul>
<li>Cacher tout ce qui était visible en étant face au bureau, ou de biais (assis et debout).</li>
<li>Ne pas faire de "plats de spaghetti", pour faciliter l'ajout de futurs équipements.</li>
</ul>
<p>Les clips permettent de plaquer les câbles sous le bureau et de les faire remonter jusqu'au bras-support de l'écran, qui permet de tout cacher (hub USB + HDMI + alimentation, branché au laptop avec un seul port USB-C).</p>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="gimme-the-light">Gimme the light<a href="https://vinceops.me/remote-bureau-diy#gimme-the-light" class="hash-link" aria-label="Lien direct vers Gimme the light" title="Lien direct vers Gimme the light">​</a></h4>
<p>Enfin, cette petite touche "kikoo" qui fait toute la différence (et un peu de rétro-éclairage la nuit) : la bande de LEDs !</p>
<p>J'ai acheté une longueur de 2 mètres (4 x 50 cm) pour <a href="https://www.amazon.fr/gp/product/B07WNQXGC1" target="_blank" rel="noopener noreferrer">12€</a>, que j'ai faite passer sur les deux chants face au mur, avec un retour de 50 cm sous le bureau, qui éclaire gentiment le sol. La bande est alimentée en USB et peut être pilotée en bluetooth ou avec sa télécommande.</p>
<blockquote>
<p>🦀 Grâce à <a href="https://blog.wokwi.com/reverse-engineering-a-bluetooth-lightbulb/" target="_blank" rel="noopener noreferrer">cet article</a>, j'ai pu récupérer les messages envoyés à la bande, puis identifier ceux qui permettaient de contrôler la couleur et l'intensité lumineuse... Et grâce à <a href="https://github.com/szeged/blurz" target="_blank" rel="noopener noreferrer">cette lib</a> Rust, alterner le Rouge &amp; Vert <strong>depuis mon laptop</strong>. J'ai donc bien envie de bricoler un plugin Jest qui rythmerait mes sessions de red/green/refacto en TDD 🤩.</p>
</blockquote>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="bilan">Bilan<a href="https://vinceops.me/remote-bureau-diy#bilan" class="hash-link" aria-label="Lien direct vers Bilan" title="Lien direct vers Bilan">​</a></h2>
<p>Du côté des coûts :</p>
<ul>
<li>Environ 263€ pour le meuble (+ une chute de 110 cm de plan)</li>
<li>Environ 114€ d'accessoires (j'ai utilisé un dixième des clips et du ruban double-face)</li>
</ul>
<p>Du côté du temps :</p>
<ul>
<li>Environ 4 heures pour le meuble</li>
<li>Environ 2 heures pour l'assemblage du bras, le <em>cable management</em>, le passage des LEDs</li>
<li>4 bonnes heures à : récupérer les échanges Bluetooth entre mon smartphone et la bande de LEDs, configurer le bluetooth sur ma machine toute neuve (Arch 5.9+) et m'éclater comme un gosse avec Rust et les couleurs 🤦😂...</li>
</ul>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Pimped desk" src="https://vinceops.me/assets/images/final-desk-blue-b704c9ebe58905142fe6f295cb6dda13.jpg" width="650" height="460" class="img_BhpN"></p></div>
<p>J'étais parti pour fabriquer mon propre tiroir, mais cela nécessite beaucoup plus de matériel pour être bien fait. Du coup, j'hésite encore entre plusieurs modèles de caissons noirs en acier.</p>
<p>Mon siège vient d'Ikea, modèle "VOLMAR" (acheté 300€ en 2016).</p>
<ul>
<li>Le clavier est un Logitech K800 (49€ lors d'une promotion Amazon, il y a un mois).</li>
<li>La souris est le modèle 2020 "ergonomique" de VicTising (15€).</li>
<li>Le hub USB est une sous-marque aussi, à 35€ (HDMI + ports USB + USB-C power).</li>
<li>Je projette d'acheter l'écran 27" iiyama ProLite XUB2792QSU pour remplacer l'actuel 24".</li>
</ul>
<p>À très vite pour un article plus technique 🎅 !</p>]]></content:encoded>
            <category>productivité</category>
            <category>télétravail</category>
            <category>bureau</category>
        </item>
        <item>
            <title><![CDATA[GitLab CI : Intégré comme jamais]]></title>
            <link>https://vinceops.me/gitlab-ci-cd</link>
            <guid>https://vinceops.me/gitlab-ci-cd</guid>
            <pubDate>Thu, 12 Nov 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Dernièrement, je constate que la CI (Continuous Integration) est un skill relativement rare chez les développeurs, même pour des profils expérimentés. Sans en être un expert absolu, je voulais en livrer ma vision et quelques éléments pour démarrer. Je présente dans cet article une intégration continue "type" que j'ai utilisée dans l'un de mes projets, avec GitLab CI et mon propre serveur runner.]]></description>
            <content:encoded><![CDATA[<p>Dernièrement, je constate que la CI (<em>Continuous Integration</em>) est un <em>skill</em> relativement rare chez les développeurs, même pour des profils expérimentés. Sans en être un expert absolu, je voulais en livrer <strong>ma</strong> vision et quelques éléments pour démarrer. Je présente dans cet article une intégration continue "type" que j'ai utilisée dans l'un de mes projets, avec GitLab CI et mon propre serveur <em>runner</em>.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="rappel-sur-la-ci">Rappel sur la CI<a href="https://vinceops.me/gitlab-ci-cd#rappel-sur-la-ci" class="hash-link" aria-label="Lien direct vers Rappel sur la CI" title="Lien direct vers Rappel sur la CI">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="lobjectif">L'objectif<a href="https://vinceops.me/gitlab-ci-cd#lobjectif" class="hash-link" aria-label="Lien direct vers L'objectif" title="Lien direct vers L'objectif">​</a></h3>
<p>La plupart du temps, les développeurs écrivent du code. L'intégration continue encourage la fusion (<em>merge</em>) fréquente de ce code dans le projet, plutôt que d'attendre l'approche d'une livraison pour y intégrer tous les derniers développements simultanément. Cela permet de drastiquement diminuer la quantité de conflits à résoudre entre <em>feature branches</em>. Les équipes de <a href="https://en.wikipedia.org/wiki/Quality_assurance" target="_blank" rel="noopener noreferrer">QA</a> apprécient aussi la réduction de la durée/intensité de leurs sessions de test.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="en-pratique">En pratique<a href="https://vinceops.me/gitlab-ci-cd#en-pratique" class="hash-link" aria-label="Lien direct vers En pratique" title="Lien direct vers En pratique">​</a></h3>
<p>Pour augmenter la fréquence des fusions, il est impératif que chaque développeur sache le plus rapidement possible si ses modifications entraînent des régressions. La CI a pour but d'<strong>automatiser les tâches garantissant la santé du code</strong> : <em>lint</em>, compilation, mesure de qualité, exécution des tests, etc. Ces tâches sont ainsi exécutées à chaque modification du code d'une branche, pour déterminer si le nouveau code est intégrable sans risque. Les erreurs sont ainsi détectées très tôt dans le processus de développement (<em>fail fast!</em>).</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="CI process" src="https://vinceops.me/assets/images/ci-pipeline-process-4449b2059a2d22519a657e16d8a9fb5e.jpg" width="454" height="262" class="img_BhpN"></p></div>
<p>En plus des outils de mesure de la qualité et des tests automatisés déjà présents dans le projet, il faut investir dans l'écriture d'un <strong>pipeline</strong> d'intégration continue. Cet investissement est vite rentabilisé par un gain significatif de productivité (confort, confiance).</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Une bonne pratique consiste à configurer l'interdiction de <em>Merge</em> une branche dont le pipeline d'intégration a échoué, puisque le code est jugé non-conforme. La branche principale gagne naturellement en "capital confiance", quand on sait que le code qu'elle contient est forcément validé (en plus d'avoir été revu par des collègues).</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="ce-que-jutilise--gitlab-ci">Ce que j'utilise : GitLab CI<a href="https://vinceops.me/gitlab-ci-cd#ce-que-jutilise--gitlab-ci" class="hash-link" aria-label="Lien direct vers Ce que j'utilise : GitLab CI" title="Lien direct vers Ce que j'utilise : GitLab CI">​</a></h2>
<p>GitLab CI est la solution <em>open source</em> de CI/CD intégrée à la plateforme GitLab, elle-même open source. Chaque <em>push</em> sur chaque branche du projet va déclencher l'exécution du pipeline d'intégration. Elle est bien <a href="https://docs.gitlab.com/ee/ci/quick_start/" target="_blank" rel="noopener noreferrer">documentée</a> et gratuite dans la limite de 400 minutes par mois sur les <em>shared runners</em> : au-delà, il faut payer, ou utiliser son propre <em>runner</em>.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Pipeline" src="https://vinceops.me/assets/images/gitlab-ci-pipeline-1eeef0e51810d207119da4f8f7d033ce.jpg" width="942" height="149" class="img_BhpN"><br>
<em>Pipeline visible sur la page d'une Merge Request</em></p></div>
<p>Il existe d'autres solutions, comme les <a href="https://github.com/features/actions" target="_blank" rel="noopener noreferrer">GitHub Actions</a>, <a href="https://travis-ci.org/" target="_blank" rel="noopener noreferrer">Travis</a> ou <a href="https://circleci.com/" target="_blank" rel="noopener noreferrer">CircleCI</a>. Contrairement à ses concurrents, GitLab CI n'offre <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/224124" target="_blank" rel="noopener noreferrer">pas encore</a> de <em>runner</em> "clé en main" sous Mac OS (donc pas de <em>build</em> Xcode).</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Dans mon équipe, la compilation de nos applications mobiles (<strong>iOS</strong> inclus) est confiée à <a href="https://www.bitrise.io/" target="_blank" rel="noopener noreferrer">Bitrise</a>.</p></div></div>
<p>Enfin, il est possible de transformer n'importe quelle machine (PC, Macbook, carte ARM, serveur dédié...) en <em>runner</em>, en y installant <a href="https://docs.gitlab.com/runner/" target="_blank" rel="noopener noreferrer">GitLab Runner</a>. J'en dis plus dans la suite de l'article !</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="-dessine-moi-un-pipeline">🔄 Dessine-moi un pipeline<a href="https://vinceops.me/gitlab-ci-cd#-dessine-moi-un-pipeline" class="hash-link" aria-label="Lien direct vers 🔄 Dessine-moi un pipeline" title="Lien direct vers 🔄 Dessine-moi un pipeline">​</a></h3>
<p>Chaque pipeline est constitué d'un ou plusieurs <strong>jobs</strong> (travaux) regroupés en <strong>stages</strong> (étapes). Les <em>jobs</em> d'une même <em>stage</em> sont exécutés en parallèle. Si un <em>job</em> échoue, la <em>stage</em> échoue et interrompt l'exécution du pipeline : les <em>stages</em> suivantes ne sont pas exécutées. <em>À moins que le job n'ait été <a href="https://docs.gitlab.com/ee/ci/yaml/#allow_failure" target="_blank" rel="noopener noreferrer">autorisé à échouer</a></em>. La terminologie change d'une plateforme à une autre, mais on retrouve souvent la même construction. <a href="https://circleci.com/docs/2.0/workflows/" target="_blank" rel="noopener noreferrer">CircleCI</a> parle de Workflows et de Jobs, <a href="https://docs.travis-ci.com/user/build-stages/" target="_blank" rel="noopener noreferrer">Travis CI</a> de Build Stages et de Jobs.</p>
<p>La documentation des <a href="https://docs.gitlab.com/ee/ci/yaml/" target="_blank" rel="noopener noreferrer">Pipelines GitLab CI</a> est très bien faite et il existe aussi de nombreuses <strong><a href="https://gitlab.com/gitlab-org/gitlab-foss/tree/master/lib/gitlab/ci/templates" target="_blank" rel="noopener noreferrer"><em>templates</em></a> officielles prêtes à l'usage</strong>.</p>
<blockquote>
<p>👮 Gardons à l'esprit, pour la suite de l'article, qu'un pipeline se doit d'être <strong>déterministe</strong> et aussi <strong>rapide</strong> que possible.</p>
</blockquote>
<p>La définition du pipeline se fait dans un fichier <code>.gitlab-ci.yml</code> à la racine du projet. GitLab détecte automatiquement ce fichier. Dans mon projet (<em>mono-repo, fullstack</em>), j'ai défini les <em>stages</em> suivant :</p>
<div class="language-yaml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-yaml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># .gitlab-ci.yml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">stages</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> build</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">and</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> deployment</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Et je vais présenter, ici, deux <em>jobs</em> de la <em>stage</em> <code>build-and-test</code> : la construction de l'image docker de l'application <strong>frontend</strong> et celle de l'application <strong>backend</strong>. Ces <em>jobs</em> sont exécutés, <strong>à la racine du dépôt</strong>, à chaque fois qu'une modification du code est poussée dans ce dernier.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Pipeline" src="https://vinceops.me/assets/images/pipeline-stages-and-jobs-8bfa8dfa9e1bb46def48cc00a7119d44.jpg" width="328" height="204" class="img_BhpN"><br>
<em>Quand toutes les stages sont exécutées avec succès, le commit est "passé".</em></p></div>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="frontend">Frontend<a href="https://vinceops.me/gitlab-ci-cd#frontend" class="hash-link" aria-label="Lien direct vers Frontend" title="Lien direct vers Frontend">​</a></h4>
<div class="language-yaml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-yaml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># .gitlab-ci.yml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># [...]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">🏠 Frontend </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">Build and tests</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> build</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">and</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> docker</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">stable</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> docker build </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">f app/Dockerfile </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">t frontend</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">build .</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le <em>job</em> nommé <code>🏠 Frontend - Build and tests</code>, associé à la <code>stage</code> "<code>build-and-test</code>", utilise l' <code>image</code> docker <code>docker:stable</code> pour exécuter son <code>script</code> qui consiste en un <code>docker build</code>. Le Dockerfile <code>app/Dockerfile</code> va :</p>
<ul>
<li>Installer les modules NPM (<code>yarn install</code>)</li>
<li>Valider la bonne compilation de l'ensemble de la <em>codebase</em> TypeScript (<code>yarn tsc</code>)</li>
<li>S'assurer du bon <em>linting</em> du code (<code>yarn lint</code>)</li>
<li>Vérifier que le projet puisse être construit (<code>yarn build</code>)</li>
<li>Exécuter les tests unitaires et end-to-end (Cypress) (<code>yarn test</code> et <code>yarn e2e</code>)</li>
</ul>
<div class="language-docker codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-docker codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># ./app/Dockerfile</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Image cypress : node, npm, yarn + cypress et ses dépendances</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">FROM</span><span class="token instruction"> cypress/base:14.15.0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">WORKDIR</span><span class="token instruction"> /app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">ENV</span><span class="token instruction"> NODE_ENV=</span><span class="token instruction string" style="color:#e3116c">'development'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">ENV</span><span class="token instruction"> TZ=</span><span class="token instruction string" style="color:#e3116c">'UTC'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">ENV</span><span class="token instruction"> CI=true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># dans ce projet fullstack, le répertoire ./app contient le frontend</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">ARG</span><span class="token instruction"> FRONTEND_DIR=</span><span class="token instruction string" style="color:#e3116c">'/app'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># le frontend et le backend sont des yarn workspaces: chacun son package.json</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">COPY</span><span class="token instruction"> </span><span class="token instruction variable" style="color:#36acaa">${FRONTEND_DIR}</span><span class="token instruction">/package.json /app/package.json</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">COPY</span><span class="token instruction"> yarn.lock /app/yarn.lock</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">RUN</span><span class="token instruction"> yarn install --frozen-lockfile --prefer-offline --no-progress --no-emoji</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">ADD</span><span class="token instruction"> </span><span class="token instruction variable" style="color:#36acaa">${FRONTEND_DIR}</span><span class="token instruction">/. /app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">RUN</span><span class="token instruction"> yarn tsc:all</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">RUN</span><span class="token instruction"> yarn lint</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">RUN</span><span class="token instruction"> yarn build</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">RUN</span><span class="token instruction"> yarn test</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">RUN</span><span class="token instruction"> yarn cypress install</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">RUN</span><span class="token instruction"> yarn e2e:ci # start-server-and-test start http://localhost:8000 cypress run</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token instruction keyword" style="color:#00009f">CMD</span><span class="token instruction"> yarn start</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Si l'une de ces tâches échoue, la commande <code>docker build</code> échoue, entraînant l'échec du <em>job</em>.</p>
<p><strong>Il est évidemment possible d'exécuter ces commandes <code>yarn</code> directement dans le <code>script</code> du <em>job</em></strong> :</p>
<div class="language-yaml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-yaml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># .gitlab-ci.yml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># [...]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">🏠 Frontend </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">Build and tests</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> build</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">and</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">14.15.0</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">stretch</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">slim </span><span class="token comment" style="color:#999988;font-style:italic"># on utilise une image node directement !</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn install </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">frozen</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">lockfile </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">prefer</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">offline </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">no</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">progress </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">no</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">emoji</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn tsc</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">all</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn lint</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># ...</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>L'avantage d'exécuter ces tâches en construisant une image Docker est de profiter de son <a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache" target="_blank" rel="noopener noreferrer">build cache</a> incrémental 🐋, quand le pipeline est exécuté systématiquement sur la même machine. Ainsi, à la prochaine exécution de <code>docker build</code>, <code>yarn install</code> ne sera pas ré-exécuté si <code>package.json</code> n'a pas été modifié. Même principe pour <code>lint</code>, <code>build</code>, <code>test</code> : pas exécutés si le code à copier dans <code>./app</code> n'a pas été modifié.</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Pour davantage d'explications, consultez <a href="https://www.docker.com/blog/speed-up-your-development-flow-with-these-dockerfile-best-practices/" target="_blank" rel="noopener noreferrer">cet article</a> 🐳.<br>
<!-- -->Et, Oui, j'aurais pu utiliser un build <a href="https://docs.docker.com/develop/develop-images/multistage-build/" target="_blank" rel="noopener noreferrer">multi-stages</a> mais ce n'est pas le sujet de l'article !</p></div></div>
<img src="https://media.giphy.com/media/l0HlBTpop4XgVOjZK/giphy.gif" alt="pipeline" style="width:350px;margin:20px auto;display:block">
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="backend">Backend<a href="https://vinceops.me/gitlab-ci-cd#backend" class="hash-link" aria-label="Lien direct vers Backend" title="Lien direct vers Backend">​</a></h4>
<div class="language-yaml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-yaml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># .gitlab-ci.yml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># [...]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">🏗 Backend </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">Build and tests</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> build</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">and</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> docker/compose</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> docker build </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">f backend/Dockerfile </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">t backend</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">build .</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> docker</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">compose </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">f backend/ci/docker</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">compose.yml up </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">force</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">recreate </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">exit</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">code</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">from backend</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le <em>job</em> construit une image Docker à partir du Dockerfile <code>backend/Dockerfile</code>, à la manière du projet frontend (<code>install</code>, <code>lint</code>, <code>build</code>, <code>test</code>...).</p>
<p>Si l'image est construite, alors <strong><code>docker-compose</code></strong> est utilisé pour lancer deux containers : un pour lancer les tests d'intégration et <em>end-to-end</em> de l'application <strong>backend</strong>, un autre pour l'émulateur de la base de données (<a href="https://firebase.google.com/docs/firestore" target="_blank" rel="noopener noreferrer">Firestore</a>).</p>
<div class="language-yaml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-yaml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># backend/ci/docker-compose.yml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'3.2'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">services</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">backend</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> backend</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">environment</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">FIRESTORE_EMULATOR_HOST</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'firestore-emulator:8081'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">FIREBASE_PROJECT_ID</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'firestore-testing'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">CI</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'true'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">depends_on</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> firestore</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">emulator</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">command</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> bash</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">c</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        for ((i=0;i&lt;30;++i));</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        do curl -s firestore-emulator:8081 &amp;&amp; break || (echo "Waiting for firestore emulator..." &amp;&amp; sleep 1);</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        done;</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        yarn integration &amp;&amp; yarn e2e;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">firestore-emulator</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># using "alpine" as it is ~600MB smaller (but JDK 8+ is still required)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> google/cloud</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">sdk</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">316.0.0</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">alpine</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">expose</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">8081</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">command</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> bash</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">c</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token scalar string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        apk --update add openjdk8-jre</span><br></span><span class="token-line" style="color:#393A34"><span class="token scalar string" style="color:#e3116c">        gcloud --quiet beta emulators firestore start --project=firestore-testing --host-port 0.0.0.0:8081</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>En passant <code>--exit-code-from backend</code> à <code>docker-compose</code>, le <em>job</em> réussit seulement si la commande du service <code>backend</code> (<code>yarn integration &amp;&amp; yarn e2e</code>) réussit.</p>
<p>Kudos à mon ex CTO <a href="https://twitter.com/digitalumberjak" target="_blank" rel="noopener noreferrer">@DigitalLumberjack</a> pour cette technique 💗.</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Plutôt que d'utiliser Docker Compose afin de lancer un deuxième container pour la base de données, il est aussi possible d'utiliser les <a href="https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service" target="_blank" rel="noopener noreferrer"><strong>Services</strong></a> de GitLab CI. Cela demande moins de travail, mais ce n'est pas exécutable sur votre machine, contrairement à Docker Compose.<br>
<!-- -->Dans le cas de <code>Firestore</code>, il n'existe aucun service dédié, donc pas le choix : on télécharge l'image de Google Cloud et on lance l'émulateur à la main.</p></div></div>
<img src="https://media.giphy.com/media/NygxobfPsIHNS/giphy.gif" alt="docker-compose" style="width:350px;margin:20px auto;display:block">
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="et-cest-tout-">Et c'est tout ?<a href="https://vinceops.me/gitlab-ci-cd#et-cest-tout-" class="hash-link" aria-label="Lien direct vers Et c'est tout ?" title="Lien direct vers Et c'est tout ?">​</a></h4>
<p>C'est un bon début ! Bien sûr, on peut aller beaucoup plus loin, en intégration comme en déploiement. Pour en apprendre davantage sur les possibilités de GitLab CI, je recommande (<strong>entre autres</strong>) :</p>
<ul>
<li>Les <em>jobs</em> conditionnels, avec <a href="https://docs.gitlab.com/ee/ci/yaml/#rules" target="_blank" rel="noopener noreferrer"><code>rules</code></a>, qui remplace <a href="https://docs.gitlab.com/ee/ci/yaml/#onlyexcept-basic" target="_blank" rel="noopener noreferrer"><code>only/expect</code></a> : pratique, par exemple, pour déployer automatiquement l'application sur un environnement <a href="https://en.wikipedia.org/wiki/Deployment_environment#Staging" target="_blank" rel="noopener noreferrer">Staging</a> quand le pipeline est exécuté sur la branche <code>master</code>.</li>
<li><a href="https://docs.gitlab.com/ee/ci/yaml/#when" target="_blank" rel="noopener noreferrer"><code>when</code></a>, utilisable avec ou sans <code>rules</code>, permet avec la valeur <code>manual</code> d'ajouter des <em>jobs</em> à lancer manuellement (e.g. "Déployer en production"), mais aussi des <em>jobs</em> automatiquement lancés suite à un échec du pipeline (<code>on_failure</code>), etc.</li>
</ul>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Job manuel" src="https://vinceops.me/assets/images/manual-job-02dd875a3e4c5b45e38f5b90d4d84aa1.jpg" width="257" height="152" class="img_BhpN"><br>
<em>Job manuel : déployer en production ("master" seulement).</em></p></div>
<div class="language-yaml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-yaml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">🚀 Frontend </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">Deploy production</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> production</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">14.15.0</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">stretch</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">slim</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn install </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">frozen</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">lockfile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> echo "$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">FIREBASE_PKEY_FILE_JSON</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">" </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> base64 </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">d </span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain"> ./firebase</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">credentials.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn firebase deploy </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">token "$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">FIREBASE_TOKEN</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">rules</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">if</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'$CI_COMMIT_BRANCH == "master"'</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># seulement possible avec "master"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">when</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> manual</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ul>
<li>Les <a href="https://docs.gitlab.com/ee/ci/yaml/#artifacts" target="_blank" rel="noopener noreferrer"><code>artifacts</code></a>, fichiers conservés après l'exécution d'un <em>job</em> et téléchargeable par l'interface de GitLab. Utiles pour extraire les logs d'un test de performances, des captures d'écran et vidéos de tests Cypress, des rapports/extraits, etc.</li>
</ul>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Artifacts" src="https://vinceops.me/assets/images/job-artifacts-5182d3b5022f9b0f64dd427ff76518c3.jpg" width="281" height="192" class="img_BhpN"><br>
<em>Téléchargeables sous forme d'archive, ou à parcourir dans l'explorateur de GitLab Web</em></p></div>
<ul>
<li><a href="https://docs.gitlab.com/ee/ci/yaml/#parallel" target="_blank" rel="noopener noreferrer"><code>parallel</code></a> permettant plusieurs exécutions simultanées d'un même <em>job</em>.</li>
</ul>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Jobs simultanés" src="https://vinceops.me/assets/images/stage-with-parallel-jobs-d931131fd96b528e1e5092597ba02050.jpg" width="247" height="298" class="img_BhpN"><br>
<em>Les tests E2E d'un autre projet, répartis dans 4 instances d'un même job.</em></p></div>
<ul>
<li>
<p>L'injection de <a href="https://docs.gitlab.com/ee/ci/variables/" target="_blank" rel="noopener noreferrer">variables d'environnement</a> dans GitLab CI, rendues accessibles dans <code>.gitlab-ci.yml</code>.</p>
</li>
<li>
<p>La directive <a href="https://docs.gitlab.com/ee/ci/caching/#caching-nodejs-dependencies" target="_blank" rel="noopener noreferrer"><code>cache</code></a> qui permet de transférer des fichiers d'un <em>job</em> à un autre. Utile si vous ne pouvez/voulez pas profiter du cache de build incrémental en lançant vos <em>jobs</em> dans des <code>docker build</code>.</p>
</li>
<li>
<p>En quête de performances pour les machines virtuelles servant de <em>runners</em>, GitLab CI permet de configurer un <a href="https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching" target="_blank" rel="noopener noreferrer">cache distribué</a> (<a href="https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnerscaches3-section" target="_blank" rel="noopener noreferrer">AWS S3</a>, <a href="https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnerscachegcs-section" target="_blank" rel="noopener noreferrer">Cloud Storage</a>, Azure...).</p>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="-dessine-moi-un-runner">🏃 Dessine-moi un runner<a href="https://vinceops.me/gitlab-ci-cd#-dessine-moi-un-runner" class="hash-link" aria-label="Lien direct vers 🏃 Dessine-moi un runner" title="Lien direct vers 🏃 Dessine-moi un runner">​</a></h3>
<p>Utiliser une machine dédiée peut mener à la <strong>réduction du temps d'exécution</strong> des pipelines : meilleur <em>hardware</em> 🚀, réutilisation du cache Docker 🐳 (<code>docker build</code> plus rapide) et du cache <code>npm</code>/<code>yarn</code> 📦 (les <em>packages</em> déjà en cache ne sont pas téléchargés à nouveau).<br>
<!-- -->Accessoirement, en n'utilisant pas les <em>shared runners</em> de GitLab, on peut aussi :</p>
<ul>
<li>Éviter l'envoi de fichiers/codes sensibles sur des machines qu'on ne possède pas</li>
<li>Utiliser la CLI Xcode si disponible sur la machine hôte (macOS)</li>
<li>S'affranchir des limitations (commerciales) sur les <em>shared runners</em></li>
</ul>
<p><em>Si vous souhaitez déployer votre propre flotte de runners (kubernetes, cloud autoscaling, etc), il existe des <a href="https://docs.gitlab.com/runner/configuration/autoscale.html" target="_blank" rel="noopener noreferrer">exemples</a> officiels. Pour ce projet personnel, j'ai utilisé un seul serveur dédié.</em></p>
<p>Il suffit d'<a href="https://docs.gitlab.com/runner/install/" target="_blank" rel="noopener noreferrer">installer</a> l'utilitaire <a href="https://docs.gitlab.com/runner/" target="_blank" rel="noopener noreferrer">GitLab Runner</a> sur la machine en question (avec <code>docker</code> pour <em>executor</em>) et d'<a href="https://docs.gitlab.com/runner/register/" target="_blank" rel="noopener noreferrer">enregistrer</a> le <em>runner</em> dans votre instance GitLab. Les <em>stages</em> du pipeline seront directement exécutés sur la machine enregistrée.</p>
<blockquote>
<p>💰 Pour de meilleures performances si votre budget est serré, dans le cas d'un serveur dédié, favorisez (en priorité) un <strong>SSD</strong> plutôt qu'un disque dur mécanique. Le reste (CPU, RAM) dépendra de ce que vous ferez/lancerez dans vos pipelines. Il vous appartient d'étudier toutes les possibilités en terme de budget (votre machine de travail, un serveur dédié, une flotte de machines virtuelles <a href="https://aws.amazon.com/ec2/spot" target="_blank" rel="noopener noreferrer">spot</a>/<a href="https://cloud.google.com/compute/docs/instances/preemptible" target="_blank" rel="noopener noreferrer">préemptives</a>...).</p>
</blockquote>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="une-note-sur-cypress">Une note sur Cypress<a href="https://vinceops.me/gitlab-ci-cd#une-note-sur-cypress" class="hash-link" aria-label="Lien direct vers Une note sur Cypress" title="Lien direct vers Une note sur Cypress">​</a></h4>
<p>Si vous rencontrez des problèmes de mémoire (<code>Out of memory</code>) lorsque vous exécutez vos tests e2e utilisant Cypress, c'est peut-être dû à une <em>shared memory</em> (shm) insuffisante, Docker lui allouant 64MB par défaut. Si vous utilisez votre propre <em>runner</em>, vous pouvez augmenter celle-ci en conséquence, en passant par exemple <strong><code>--shm-size=1G</code></strong> à Docker (dans mon cas, directement à <code>docker build</code>) et en ajoutant la même configuration à <code>/etc/gitlab-runner/config.toml</code> avec le paramètre <a href="https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnersdocker-section" target="_blank" rel="noopener noreferrer">shm_size</a> :</p>
<div class="language-toml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-toml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain"># [...]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[[runners]]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  # [...]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  [runners.docker]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    # [...]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    shm_size = 1073741824</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="et-avec-un-projet-déjà-existant-">Et avec un projet déjà existant ?<a href="https://vinceops.me/gitlab-ci-cd#et-avec-un-projet-d%C3%A9j%C3%A0-existant-" class="hash-link" aria-label="Lien direct vers Et avec un projet déjà existant ?" title="Lien direct vers Et avec un projet déjà existant ?">​</a></h2>
<p><strong>Démarrez petit</strong> ! On peut utiliser une image <code>node</code> officielle et directement exécuter <code>yarn build</code>, <code>yarn test</code>, etc, dans le <code>script</code> d'un unique <em>job</em> :</p>
<div class="language-yaml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-yaml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># .gitlab-ci.yml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">stages</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> build</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">and</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">build backend</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> build</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">and</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">14.15.0</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">stretch</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">slim</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn install </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">frozen</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">lockfile </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">prefer</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">offline </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">no</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">progress </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">no</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">emoji</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn lint</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn test</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Ces quelques lignes suffisent à lancer un pipeline déjà très utile. Dans mon projet "starter" TypeScript, Gatsby, Material-UI (<a href="https://github.com/VinceOPS/gatsby-gojob-starter" target="_blank" rel="noopener noreferrer">gatsby-gojob-starter</a>), j'ai fourni deux <strong>bases</strong> de pipeline, une <a href="https://github.com/VinceOPS/gatsby-gojob-starter/blob/master/.gitlab-ci.yml" target="_blank" rel="noopener noreferrer">pour CircleCI</a>, une autre <a href="https://github.com/VinceOPS/gatsby-gojob-starter/blob/master/.gitlab-ci.yml" target="_blank" rel="noopener noreferrer">pour GitLab CI</a>. Loin d'être des modèles de perfection, elles permettent cependant de se lancer 😬&gt;.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="cd-cest-plus-quun-job">CD, "c'est plus qu'un Job"<a href="https://vinceops.me/gitlab-ci-cd#cd-cest-plus-quun-job" class="hash-link" aria-label="Lien direct vers CD, &quot;c'est plus qu'un Job&quot;" title="Lien direct vers CD, &quot;c'est plus qu'un Job&quot;">​</a></h2>
<img src="https://media.giphy.com/media/1xnQ0TsDFcrFLdlJUC/giphy.gif" alt="décollage" style="width:350px;margin:20px auto;display:block">
<p>Concernant le <a href="https://docs.gitlab.com/ee/ci/introduction/#continuous-delivery" target="_blank" rel="noopener noreferrer">Continuous Delivery</a> et le <a href="https://docs.gitlab.com/ee/ci/introduction/#continuous-deployment" target="_blank" rel="noopener noreferrer">Continuous Deployment</a>, un nouvel article serait de rigueur. Dans le cadre de mon projet personnel, j'ai un environnement de production en <strong>continuous delivery</strong> : la nouvelle version de <code>master</code> est déployée par une action manuelle. Le <em>job</em> ressemble à celui-ci :</p>
<div class="language-yaml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-yaml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">🚀 Frontend </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">Deploy production</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">14.15.0</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">stretch</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">slim</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn install </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">frozen</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">lockfile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> echo "$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">FIREBASE_PKEY_FILE_JSON</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">" </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> base64 </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">d </span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain"> ./firebase</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">credentials.json</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn firebase deploy </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">token "$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">FIREBASE_TOKEN</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">rules</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">if</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'$CI_COMMIT_BRANCH == "master"'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">when</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> manual</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Pour l'environnement de <em>staging</em>, j'utilise une version légèrement modifié de ce <em>job</em> : il est déclenché automatiquement quand une branche est fusionnée à <code>master</code> et vise <code>staging</code> comme <em>hosting target</em> pour déployer l'application vers un domaine Firebase spécifique. On parle ici de <strong>continuous deployment</strong>.</p>
<div class="language-yaml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-yaml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">🚀 Frontend </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">Deploy staging</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">stage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> deploy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">14.15.0</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">stretch</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">slim</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">script</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn install </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">frozen</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">lockfile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> echo "$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">FIREBASE_PKEY_FILE_JSON</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">" </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> base64 </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">d </span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain"> ./firebase</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">credentials.json</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> yarn firebase deploy </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">token "$</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">FIREBASE_TOKEN</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">" </span><span class="token punctuation" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">only hosting</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">staging</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">rules</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">if</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'$CI_COMMIT_BRANCH == "master"'</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><em>Il est possible de "refactorer" du YAML pour éviter les copy-paste massifs... À vous de jouer 😬.</em></p>
<p>La technique employée ici est spécifique à Firebase (<code>firebase deploy</code>). Il faut adapter le job aux contraintes <strong>techniques</strong> (Heroku ? Helm/Kubernetes ? Gestion des environnements...) et <strong>professionnelles</strong> (Sécurité ? Droits d'accès ? Politique de mise à jour...) de chaque entreprise.</p>
<p>Happy CI/CDing!</p>]]></content:encoded>
            <category>gitlab</category>
            <category>ci</category>
            <category>linux</category>
            <category>devops</category>
        </item>
        <item>
            <title><![CDATA["Refactoring" de Martin Fowler]]></title>
            <link>https://vinceops.me/refactoring-martin-fowler</link>
            <guid>https://vinceops.me/refactoring-martin-fowler</guid>
            <pubDate>Sat, 02 May 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Le blog entre en 2020 avec la présentation de Refactoring, de Martin Fowler 🚀 : la trame principale et les grandes idées.]]></description>
            <content:encoded><![CDATA[<p>Le blog entre en 2020 avec la présentation de <strong>Refactoring</strong>, de <a href="https://martinfowler.com/" target="_blank" rel="noopener noreferrer">Martin Fowler</a> 🚀 : la trame principale et les grandes idées.</p>
<p>L'article est long, mais je pense qu'il apportera l'essentiel du livre à ceux qui n'ont pas le temps de le lire... Sans priver les autres de l'envie de le faire. Et je conseille à tous de le faire 😃.</p>
<p>Cette seconde édition du livre est une réécriture (partielle) pour JavaScript. Son but est de guider les développeurs dans l'amélioration de leur code, par petites itérations, sans en changer le comportement. C'est l'exacte définition du <em>refactoring</em> : <strong>changer la structure du code, sans changer son comportement</strong>...</p>
<p>Et <strong>non</strong>, Refactoring ne signifie pas "réécrire un code moche".</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="I&amp;#39;m watching you" src="https://vinceops.me/assets/images/meme-watching-you-5b37754a7c14b5ad2a8abc478e98d0b9.jpg" width="300" height="251" class="img_BhpN"></p></div>
<p><em>Pour ceux qui ne connaissaient pas <a href="https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)" target="_blank" rel="noopener noreferrer">l'auteur</a>, je vous invite à lire son <a href="https://www.martinfowler.com/" target="_blank" rel="noopener noreferrer">excellent site</a> et à le suivre sur <a href="https://twitter.com/martinfowler" target="_blank" rel="noopener noreferrer">Twitter</a>.</em></p>
<p>L'ouvrage présente un long catalogue des techniques de refactorings, consultable <a href="https://refactoring.com/catalog/" target="_blank" rel="noopener noreferrer">sur le site officiel</a>.<br>
<!-- -->J'en profite aussi pour partager <strong><a href="https://refactoring.guru/" target="_blank" rel="noopener noreferrer">Refactoring.Guru</a></strong> qui présente du contenu de qualité sur le refactoring et les design patterns, inspiré des livres comme : <a href="https://www.oreilly.com/library/view/refactoring-improving-the/9780134757681/" target="_blank" rel="noopener noreferrer">Refactoring</a>, <a href="https://www.oreilly.com/library/view/effective-java-3rd/9780134686097/" target="_blank" rel="noopener noreferrer">Effective Java</a>, <a href="https://www.oreilly.com/library/view/design-patterns-elements/0201633612/" target="_blank" rel="noopener noreferrer">Design Patterns (GoF)</a>, <a href="https://www.oreilly.com/library/view/head-first-design/0596007124/" target="_blank" rel="noopener noreferrer">Head First Design Patterns</a>...</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="chapitre-1---un-premier-exemple-de-refactoring">Chapitre 1 - Un premier exemple de Refactoring<a href="https://vinceops.me/refactoring-martin-fowler#chapitre-1---un-premier-exemple-de-refactoring" class="hash-link" aria-label="Lien direct vers Chapitre 1 - Un premier exemple de Refactoring" title="Lien direct vers Chapitre 1 - Un premier exemple de Refactoring">​</a></h2>
<p>Le livre ouvre directement la marche avec un exemple. Le code de départ présente plusieurs imperfections (et <em><a href="https://martinfowler.com/bliki/CodeSmell.html" target="_blank" rel="noopener noreferrer">code smells</a></em>). Et ô surprise, une évolution est demandée par l'utilisateur 😱. Avant de se lancer, l'auteur effectue un rapide "état des lieux" (analyse critique).</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Le premier chapitre est consultable gratuitement et légalement <a href="https://files.thoughtworks.com/pdfs/Refactoring2-free-chapter.pdf" target="_blank" rel="noopener noreferrer">en ligne</a>. Vous pourrez y voir ledit code et toutes les étapes du refactoring, avec les explications de Martin Fowler.</p></div></div>
<p>Si l'ajout d'une fonctionnalité est compliqué à cause de l'état du code, l'auteur recommande le refactoring <strong>avant</strong> tout nouveau développement. Et avant de procéder à la moindre modification, il faut s'assurer que le code soit couvert par des <strong>tests</strong>.<br>
<!-- -->S'ensuivent plusieurs techniques de refactorings du <a href="https://refactoring.com/catalog/" target="_blank" rel="noopener noreferrer">catalogue</a>, en exécutant continuellement les tests pour vérifier que le comportement du code n'ait pas été altéré. Les refactorings appliqués sont assez communs : <a href="https://refactoring.guru/extract-method" target="_blank" rel="noopener noreferrer">Extract Function (Method)</a>, <a href="https://refactoring.guru/inline-temp" target="_blank" rel="noopener noreferrer">Inline Variable</a>, <a href="https://refactoring.guru/move-method" target="_blank" rel="noopener noreferrer">Move Method</a>, etc. Petit à petit, le code servant d'exemple devient plus lisible et maintenable.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="en-résumé">En résumé<a href="https://vinceops.me/refactoring-martin-fowler#en-r%C3%A9sum%C3%A9" class="hash-link" aria-label="Lien direct vers En résumé" title="Lien direct vers En résumé">​</a></h3>
<ul>
<li><strong>Pas de refactoring sans test</strong></li>
<li>Le refactoring :<!-- -->
<ul>
<li>est effectué en <strong>petites étapes</strong>, précédées par une avancée dans la compréhension du code</li>
<li>ne modifie pas le <strong>comportement</strong> du code : les modifications ne nécessitent pas de nouveaux tests</li>
<li>n'a pas besoin d'être violent : même une petite <strong>amélioration</strong> est bonne à prendre, <em>Boy scout rule</em>, "Laissez le camp plus propre que vous ne l'avez trouvé"</li>
</ul>
</li>
<li>Les tests existants sont exécutés <strong>continuellement</strong>, c'est notre filet de sécurité</li>
<li>Un code a été "amélioré" lorsqu'il est plus <strong>simple à modifier</strong> : la <strong>productivité</strong> du développeur est augmentée car il peut ajouter de la <strong>valeur</strong> au logiciel plus rapidement... <em>"Code should be obvious"</em>.</li>
</ul>
<p>Au risque de me répéter... Des <strong>petites étapes</strong>, appuyées par les <strong>tests</strong>. À l'image des <em>baby steps</em> du TDD, elles permettent d'éviter de longues sessions de debugging. Refactorman n'est pas un héros 😬.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Refactor-man" src="https://vinceops.me/assets/images/refactor-man-a568e891ad0a7b8be042c2e58a8db924.jpg" width="1200" height="1223" class="img_BhpN"></p></div>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="chapitre-2---les-fondements-du-refactoring">Chapitre 2 - Les fondements du Refactoring<a href="https://vinceops.me/refactoring-martin-fowler#chapitre-2---les-fondements-du-refactoring" class="hash-link" aria-label="Lien direct vers Chapitre 2 - Les fondements du Refactoring" title="Lien direct vers Chapitre 2 - Les fondements du Refactoring">​</a></h2>
<p>Martin Fowler donne une <a href="https://martinfowler.com/bliki/DefinitionOfRefactoring.html" target="_blank" rel="noopener noreferrer">définition</a> précise de Refactoring, à la fois en tant que nom et en tant que verbe :</p>
<blockquote>
<p><strong>Refactoring</strong> (nom) : Changement de la structure d'un code pour faciliter sa compréhension et sa modification, sans changer son comportement observable.</p>
</blockquote>
<p>Le comportement <strong>observable</strong> est celui connu par l'utilisateur. Il n'est pas question du comportement <strong>technique</strong> (allocations mémoires, utilisation des cycles CPU, etc.).</p>
<blockquote>
<p><strong>Refactoring</strong> (verbe) : Restructurer du code en appliquant une série de refactorings.</p>
</blockquote>
<p>Donc, quand on refactor, on applique des refactorings. La prochaine fois qu'un collègue vous dira "ce code bug, je dois faire une refacto", n'hésitez pas à prendre un air hautain et toxique pour lui expliquer qu'il dit n'importe quoi 😏.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Mauvaise utilisation du terme Refactoring" src="https://vinceops.me/assets/images/meme-should-be-refactored-9163d8e7f9dcd2c7f142ad2634287569.jpg" width="555" height="450" class="img_BhpN"></p></div>
<p>En effet, le terme est souvent mal employé (pour désigner une session de debug, voire la réécriture complète d'un code...). L'auteur a écrit un article à ce sujet : <a href="https://martinfowler.com/bliki/RefactoringMalapropism.html" target="_blank" rel="noopener noreferrer">Refactoring Malapropism</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="le-refactoring--pourquoi-">Le Refactoring : Pourquoi ?<a href="https://vinceops.me/refactoring-martin-fowler#le-refactoring--pourquoi-" class="hash-link" aria-label="Lien direct vers Le Refactoring : Pourquoi ?" title="Lien direct vers Le Refactoring : Pourquoi ?">​</a></h3>
<ul>
<li>Faciliter la compréhension du code (et par conséquent, la <em>recherche</em> de bugs)</li>
<li>Améliorer la conception (design) du logiciel</li>
<li><strong>Développer plus rapidement</strong></li>
</ul>
<p>Dans son article <a href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html" target="_blank" rel="noopener noreferrer">Design Stamina Hypothesis</a>, Martin Fowler présente l'hypothèse du <strong>seuil de rentabilité</strong> du <em>design</em> (qualité, conception), alias <em>design payoff line</em>.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="design stamina" src="https://vinceops.me/assets/images/designStaminaGraph-6ef7c671e3c16b784f0556494fb5cc04.gif" width="618" height="329" class="img_BhpN"></p></div>
<p>Sous ce seuil, il est <em>possible</em> de gagner en productivité (livrer davantage de fonctionnalités) en négligeant la qualité (le design) du code. C'est ce qu'on appelle Acheter de la <strong>dette technique</strong>. Passé ce seuil, c'est l'inverse qui se produit : le développement est ralenti, les livraisons prennent du retard, la moindre modification devient coûteuse.</p>
<p>Le refactoring permet, par l'amélioration continue du code, de maintenir un certain niveau de qualité <strong>et</strong> de productivité 🤓.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="le-refactoring--quand-">Le Refactoring : Quand ?<a href="https://vinceops.me/refactoring-martin-fowler#le-refactoring--quand-" class="hash-link" aria-label="Lien direct vers Le Refactoring : Quand ?" title="Lien direct vers Le Refactoring : Quand ?">​</a></h3>
<p>L'auteur affirme faire du refactoring <strong>en permanence</strong>, comme de nombreux développeurs qui y ont pris goût.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="That&amp;#39;s my secret, I&amp;#39;m always refactoring" src="https://vinceops.me/assets/images/meme-always-refactoring-34222ccbeb387a66c3c1a622a5e3cf52.jpg" width="666" height="375" class="img_BhpN"></p></div>
<p>Le meilleur moment est celui qui précède l'ajout d'une fonctionnalité, ou la correction d'un bug. C'est ce que Martin appelle le <strong>Refactoring préparatoire</strong>. Il s'agit d'améliorer l'état du code avant d'avoir à le modifier.</p>
<p>L'auteur définit d'autres "catégories" de refactorings, comme :</p>
<ul>
<li>Compréhension : si le code a nécessité un effort intellectuel pour être compris, alors il est certainement possible de l'améliorer. Encore une fois, <em>"Code should be obvious"</em>. Des actions aussi simples que <a href="https://refactoring.com/catalog/renameVariable.html" target="_blank" rel="noopener noreferrer">Rename Variable</a> peuvent avoir un sérieux impact.</li>
<li>Ramassage des déchets : quand on remarque que le code est mal conçu, ou inutilement complexe. Il n'a pas besoin d'être entièrement réécrit, mais on peut l'améliorer progressivement, sur la durée. "Laissez le camp plus propre que vous ne l'avez trouvé".</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Si vous faites des <a href="https://vinceops.me/git-astuces-productivite-1/">conventional commits</a>, pensez aussi à isoler vos refactorings dans un commit <code>refactor</code>. Vos collègues chargés de la revue de code apprécieront certainement.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="etc">Etc.<a href="https://vinceops.me/refactoring-martin-fowler#etc" class="hash-link" aria-label="Lien direct vers Etc." title="Lien direct vers Etc.">​</a></h3>
<p>Le chapitre est long et dense. L'article n'a pas pour vocation de couvrir tous les éléments qui donnent sa valeur au livre.</p>
<p>Néanmoins, puisque c'est un vice très répandu dans l'industrie, je partage l'une des notions abordées : la <a href="https://refactoring.guru/smells/speculative-generality" target="_blank" rel="noopener noreferrer">Speculative Generality</a>. On connait tous un dév qui écrit parfois 3 fois plus de code que nécessaire "juste au cas où". Et il est même souvent "prêt à parier que ça va servir".<br>
<!-- -->L'auteur avance l'idée qu'avec un refactoring continu, il est très facile de rendre le code plus flexible <strong>au besoin</strong>, plutôt que <strong>d'anticiper</strong> cette flexibilité (flexi-complexité...). C'est l'opposition entre le <em>Use-case driven development</em> et ce que j'appelle le <em>"Just in case" driven development</em>.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Over engineering" src="https://vinceops.me/assets/images/over-engineering-fe87eb887f7d489d8fdc5274d8912675.jpg" width="823" height="339" class="img_BhpN"><br>
<em>Over-engineering...</em></p></div>
<p><em>Speculative Generality</em> est aussi abordé dans le chapitre 3 sur les <strong>code smells</strong>. Dans ce chapitre 2, Martin Fowler parle plus précisément de "Speculative flexibility".</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="chapitre-3---les-smells-dans-le-code">Chapitre 3 - Les Smells dans le code<a href="https://vinceops.me/refactoring-martin-fowler#chapitre-3---les-smells-dans-le-code" class="hash-link" aria-label="Lien direct vers Chapitre 3 - Les Smells dans le code" title="Lien direct vers Chapitre 3 - Les Smells dans le code">​</a></h2>
<p><strong>Une longue série de Code smells</strong>, voilà ce qu'est ce (court) chapitre coécrit avec Kent Beck, l'auteur de <a href="https://www.oreilly.com/library/view/test-driven-development/0321146530/" target="_blank" rel="noopener noreferrer">Test Driven Development: by Example</a> qui est aussi le créateur du "TDD".</p>
<p><a href="https://refactoring.guru/smells/large-class" target="_blank" rel="noopener noreferrer">Large class</a>, <a href="https://refactoring.guru/smells/divergent-change" target="_blank" rel="noopener noreferrer">Divergent Change</a>, <a href="https://refactoring.guru/smells/shotgun-surgery" target="_blank" rel="noopener noreferrer">Shotgun Surgery</a>, <a href="https://refactoring.guru/smells/duplicate-code" target="_blank" rel="noopener noreferrer">Duplicated code</a>... Retrouvez-les sur <a href="https://refactoring.guru/refactoring/smells" target="_blank" rel="noopener noreferrer">Refactoring.guru</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="looks-familiar"><em>Looks familiar...</em><a href="https://vinceops.me/refactoring-martin-fowler#looks-familiar" class="hash-link" aria-label="Lien direct vers looks-familiar" title="Lien direct vers looks-familiar">​</a></h3>
<p>Au sujet de <strong>Large Class</strong>, <strong>Divergent Change</strong> et <strong>Shotgun Surgery</strong>, je trouve inévitable le rapprochement avec le <a href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html" target="_blank" rel="noopener noreferrer">Single Responsibility Principle</a> (SRP) d'Uncle Bob, trop souvent mal interpété. En effet, celui-ci ne stipule pas qu'un module ne devrait <strong>faire qu'une seule chose</strong> mais qu'il ne devrait <strong>avoir qu'une seule raison de changer</strong>.</p>
<blockquote>
<p>"Regroupez les choses qui changent pour les mêmes raisons. Séparez celles qui changent pour des raisons différentes".</p>
</blockquote>
<p>En d'autres termes, le SRP (<strong>S</strong> de <a href="https://en.wikipedia.org/wiki/SOLID" target="_blank" rel="noopener noreferrer">SOLID</a>) a pour objectif de <strong>limiter l'impact des changements effectués</strong> dans le code. On peut considérer que c'est ce que préconise aussi le livre, avec ces <em>smells</em>.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="chapitre-4---construire-les-tests">Chapitre 4 - Construire les tests<a href="https://vinceops.me/refactoring-martin-fowler#chapitre-4---construire-les-tests" class="hash-link" aria-label="Lien direct vers Chapitre 4 - Construire les tests" title="Lien direct vers Chapitre 4 - Construire les tests">​</a></h2>
<p>Martin Fowler explique la valeur des tests automatisés, leur nécessité dans le refactoring, et le temps qu'ils font économiser en "debugging" pour mieux le réinvestir dans la production de valeur ajoutée.</p>
<p>Si vous êtes, comme moi, habitué et rompu au TDD, ce chapitre ne sera pas le plus passionnant de l'ouvrage. Il a cependant le mérite de présenter les fondamentaux des tests unitaires et de recommander le TDD 🔥.</p>
<blockquote>
<p>When you get a bug report, start by writing a unit test that exposes the bug.</p>
</blockquote>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="résumé">Résumé<a href="https://vinceops.me/refactoring-martin-fowler#r%C3%A9sum%C3%A9" class="hash-link" aria-label="Lien direct vers Résumé" title="Lien direct vers Résumé">​</a></h2>
<p>Puisque tous les chapitres restants présentent le catalogue <a href="https://refactoring.com/catalog/" target="_blank" rel="noopener noreferrer">disponible en ligne</a>, je passe directement au résumé 🎉.</p>
<p>Au-delà des techniques de refactorings présentées, j'ai apprécié la lecture de cet ouvrage aussi <strong>sage</strong> que <strong>pragmatique</strong>. Martin Fowler offrait, déjà en 2000, une solution à certains "travers" de l'industrie que l'on subit encore en 2020. J'aurais d'ailleurs souhaité le lire il y a 10 ans, quand j'ai écrit mes premières lignes de code en tant que Développeur "professionnel".</p>
<p>Quand on démarre un projet, il est impératif d'écrire le minimum de code pour répondre au besoin exprimé, qui est souvent encore mal compris et mal connu. Plus un code est simple, moins il demande d'effort en refactoring... Refactoring qui facilite son évolution tout en contenant sa complexité (inexorablement amenée à croître). Ce qui implique une vélocité préservée pour les développeurs. Comme le dit l'auteur dans le chapitre 3 :</p>
<blockquote>
<p>After all, software is meant to be soft.</p>
</blockquote>
<p>Puisque le refactoring ne doit pas être effectué sans test, et puisqu'il doit être effectué par petites itérations, c'est un parfait associé du <strong>TDD</strong>. Mieux que ça, il fait partie intégrante de son mantra "Red, Green, Refactor".</p>
<p>Je conclurai en vous recommandant chaudement la lecture et en citant cette punchline (que j'adore) présente sur la couverture :</p>
<blockquote>
<p><strong>Any fool can write code that a computer can understand. Good programmers write code that humans can understand</strong>.</p>
</blockquote>]]></content:encoded>
            <category>livres</category>
            <category>apprentissage</category>
            <category>productivité</category>
        </item>
        <item>
            <title><![CDATA[Nest Serverless : Firebase Functions]]></title>
            <link>https://vinceops.me/nest-serverless-firebase-functions</link>
            <guid>https://vinceops.me/nest-serverless-firebase-functions</guid>
            <pubDate>Thu, 05 Dec 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Nest est mon framework Node.js préféré et aussi mon framework de travail. Je l'ai présenté sur ce blog l'année dernière et l'article est toujours d'actualité si tu veux y jeter un œil. Je l'utilise très souvent dans mes projets Node.js : Rest API, serveur GraphQL, micro-services, CLI, scripts, etc.]]></description>
            <content:encoded><![CDATA[<p><a href="https://nestjs.com/" target="_blank" rel="noopener noreferrer">Nest</a> est mon framework Node.js préféré et aussi mon framework de travail. Je l'ai présenté sur ce blog l'année dernière et <a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait/"><strong>l'article</strong> est toujours d'actualité si tu veux y jeter un œil</a>. Je l'utilise très souvent dans mes projets Node.js : Rest API, serveur GraphQL, micro-services, CLI, scripts, etc.</p>
<p>Récemment, c'est avec Nest que j'ai décidé de développer quelques <em>Functions</em>. Dans cet article, je vais rappeler ce que sont les Functions puis présenter une façon simple d'y intégrer Nest. <em>En l'occurrence, avec <a href="https://firebase.google.com/docs/functions" target="_blank" rel="noopener noreferrer">Firebase Functions</a> (<a href="https://firebase.google.com/" target="_blank" rel="noopener noreferrer">Firebase</a> avec des <a href="https://cloud.google.com/functions/" target="_blank" rel="noopener noreferrer">Cloud Functions</a>).</em></p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="faas--functions-as-a-service">FaaS : Functions As A Service<a href="https://vinceops.me/nest-serverless-firebase-functions#faas--functions-as-a-service" class="hash-link" aria-label="Lien direct vers FaaS : Functions As A Service" title="Lien direct vers FaaS : Functions As A Service">​</a></h2>
<p>Les Functions permettent de déployer et d'exécuter du code sur un serveur qui ne nous appartient pas. Zéro minute consacrée à la configuration, la sécurisation et l'entretien des machines. Tout ce qui est demandé au développeur, c'est d'écrire son code en respectant quelques règles (langage, structure, temps d'exécution...), puis de le déployer via une CLI, ou à la main.</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Chez Amazon, le service s'appelle <a href="https://aws.amazon.com/lambda/features/" target="_blank" rel="noopener noreferrer">AWS Lambda</a>. Chez Google, c'est <a href="https://cloud.google.com/functions/" target="_blank" rel="noopener noreferrer">Cloud Functions</a>, Microsoft a les <a href="https://azure.microsoft.com/fr-fr/services/functions/" target="_blank" rel="noopener noreferrer">Azur Functions</a>. Les <a href="https://www.cloudflare.com/products/cloudflare-workers/" target="_blank" rel="noopener noreferrer">CloudFlare Workers</a> utilisent directement V8 (pas Node.js), mais l'import de modules NPM est possible et WebAssembly est supporté 🎉.</p></div></div>
<p>L'exécution dudit code peut ensuite être déclenchée par un appel HTTP et/ou par un évènement : un <a href="https://docs.aws.amazon.com/lambda/latest/dg/with-s3-example.html" target="_blank" rel="noopener noreferrer">fichier déposé sur AWS S3</a>, un <a href="https://firebase.google.com/docs/functions/auth-events#trigger_a_function_on_user_creation" target="_blank" rel="noopener noreferrer">utilisateur inscrit dans Firebase Authentication</a>, etc.</p>
<p>Le FaaS offre de nombreux avantages :</p>
<ul>
<li>Un déploiement et une disponibilité quasi instantannés du code</li>
<li>Pas de serveur à louer, configurer, maintenir</li>
<li>Auto-scaling : la montée en charge (comme la baisse...) est assurée par le service</li>
<li>Une tarification à la carte dépendante du nombre d'exécutions, de leur durée, de la mémoire vive allouée</li>
</ul>
<p>Et présente quelques limitations par nature et/ou fournisseur :</p>
<ul>
<li>Plafond de ressources, d'exécutions simultanées, de durée d'exécution</li>
<li>Passé un délai d'inactivité, un délai de démarrage (<em>cold start</em>) est à prévoir à la prochaine exécution</li>
</ul>
<hr>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="dessine-moi-une-function">Dessine-moi une Function<a href="https://vinceops.me/nest-serverless-firebase-functions#dessine-moi-une-function" class="hash-link" aria-label="Lien direct vers Dessine-moi une Function" title="Lien direct vers Dessine-moi une Function">​</a></h2>
<p>On installe <code>firebase-tools</code> pour utiliser la CLI de Firebase, puis on crée le projet :</p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">npm i -g firebase-tools</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">mkdir my-cat-in-the-cloud &amp;&amp; cd my-cat-in-the-cloud</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">firebase login</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">firebase projects:list # vérifie la bonne authentification</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">firebase init functions # crée un projet ou utilise un existant</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">* Please select an option: Create a new project</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">* What language would you like to use to write Cloud Functions? TypeScript # 💖</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">* Do you want to use TSLint to catch probable bugs and enforce style? No # ESLint ftw</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">* Do you want to install dependencies with npm now? No # on va s'en occuper nous-même</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>La CLI génère <code>firebase.json</code> et, le plus intéressant, <code>./functions</code>. Si on étudie rapidement ce dernier avant de l'effacer (<strong>#yolo</strong>), on voit dans <code>package.json</code> que sont inclus : <code>firebase-admin</code>,
<code>firebase-functions</code> (<em>dependencies</em>) et <code>typescript</code>, <code>firebase-functions-test</code> (<em>dev dependencies</em>). Quant à <code>src/index.ts</code> :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> functions </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'firebase-functions'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Start writing Firebase Functions</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// https://firebase.google.com/docs/functions/typescript</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> helloWorld </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> functions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">https</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">onRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  response</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">send</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Hello from Firebase!'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Il expose seulement une <em>function</em> <code>helloWorld</code> qui peut être exécutée localement de deux manières :</p>
<ul>
<li><code>yarn serve</code> pour la servir avec un serveur HTTP: <a href="http://localhost:5000/my-cat-in-the-cloud/us-central1/helloWorld" target="_blank" rel="noopener noreferrer">http://localhost:5000/my-cat-in-the-cloud/us-central1/helloWorld</a> <em>("my-cat-in-the-cloud" étant le nom de mon répertoire <strong>et</strong> de mon projet Firebase)</em></li>
<li><code>yarn start</code> (ou <code>firebase functions:shell</code>) pour l'utiliser directement en mode shell :</li>
</ul>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">$ yarn start</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔  functions: Emulator started at http://localhost:5000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">i  functions: Loaded functions: helloWorld</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">firebase &gt; helloWorld()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Sent request to function.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">firebase &gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">RESPONSE RECEIVED FROM FUNCTION: 200, Hello from Firebase!</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Dans ce code, pas de framework Web particulier : seulement une fonction <code>onRequest</code> qui prend en paramètre un callback de type Requête-Réponse.</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Le fichier <code>firebase.json</code> situé au même niveau que le répertoire <code>./functions</code> permet la configuration (et le déploiement) des différents services de Firebase (Hosting, Functions, Storage, Firestore...).</p></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="release-the-kraken-cat">Release the <del>Kraken</del> Cat<a href="https://vinceops.me/nest-serverless-firebase-functions#release-the-kraken-cat" class="hash-link" aria-label="Lien direct vers release-the-kraken-cat" title="Lien direct vers release-the-kraken-cat">​</a></h2>
<p>Comme annoncé plus haut, on va supprimer <code>./functions</code> ! ... Et créer un projet Nest à la place.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="all-the-things" src="https://vinceops.me/assets/images/all-the-things-b63ece45e05b7e3131869a0247a4fbac.jpg" width="461" height="300" class="img_BhpN"></p></div>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">rm -rf functions</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">npm i -g @nestjs/cli # si vous ne l'avez pas déjà installé</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">nest new api &amp;&amp; cd api</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">yarn &amp;&amp; yarn add firebase-functions firebase-admin</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Puisque le projet Nest a été nommé <strong><code>api</code></strong>, on change la propriété <strong><code>"source"</code></strong> des <code>"functions"</code> dans <code>firebase.json</code> :</p>
<div class="language-json codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-json codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"functions"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"predeploy"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm --prefix \"$RESOURCE_DIR\" run build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"source"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"api"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le fichier <code>api/src/main.ts</code> doit <strong>exposer une Function</strong>, que l'on nomme très originalement <code>api</code> :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> NestFactory </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@nestjs/core'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> ExpressAdapter </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@nestjs/platform-express'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> express </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'express'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> functions </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'firebase-functions'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> AppModule </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./app.module'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">startNestApplication</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">expressApp</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Express</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Application</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> app </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> NestFactory</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">AppModule</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ExpressAdapter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">expressApp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> server </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">express</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">startNestApplication</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">server</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">catch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Nest did not start'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> api </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> functions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">region</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'europe-west1'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">https</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">onRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">server</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Notez la configuration de la <strong>région</strong> avec <code>europe-west1</code>, afin de diminuer la latence entre mes utilisateurs et ma Function, une fois celle-ci déployée.</p></div></div>
<p>Ensuite, la CLI de Firebase doit connaître le <strong>point d'entrée</strong> de notre Function. Il faut ajouter une propriété <code>"main"</code> ayant pour valeur <code>"dist/main.js"</code> dans le <code>package.json</code> généré par <code>@nestjs/cli</code>.</p>
<p>Reste à compiler puis à exécuter !</p>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">$ yarn build &amp;&amp; firebase serve --only functions</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔  functions: Emulator started at http://localhost:5000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">i  functions: Watching "/home/vince/blog/my-cat-in-the-cloud/api" for Cloud Functions...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&gt;  [Nest] 20843 - [NestFactory] Starting Nest application...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔  functions[api]: http function initialized (http://localhost:5000/my-cat-in-the-cloud/europe-west1/api).</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># [...]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&gt;  [Nest] 20903 - [NestApplication] Nest application successfully started +2ms</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>On vérifie que l'API répond à nos requêtes :</p>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">$ curl http://localhost:5000/my-cat-in-the-cloud/europe-west1/api</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Hello World! # Ça fonctionne 🎉</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Et c'est gagné !</p>
<img src="https://media.giphy.com/media/l0IsIC9ZNOELYmuqc/giphy.gif" alt="c'est gagné" style="display:block;margin:0 auto 25px auto;width:280px;height:200px">
<p>Pour <strong>déployer la Function</strong>, il faut indiquer à Firebase quelle version du runtime (Node.js) utiliser via <code>package.json</code>, et utiliser la commande <code>deploy</code> :</p>
<div class="language-json codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-json codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"engines"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"node"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"10"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">$ firebase deploy --only functions</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">=== Deploying to 'my-cat-in-the-cloud'...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">i  deploying functions</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Running command: npm --prefix "$RESOURCE_DIR" run build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&gt; functions@0.0.1 prebuild /home/vince/blog/my-cat-in-the-cloud/api</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&gt; rimraf dist</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&gt; functions@0.0.1 build /home/vince/blog/my-cat-in-the-cloud/api</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&gt; nest build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔  functions: Finished running predeploy script.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">i  functions: ensuring necessary APIs are enabled...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔  functions: all necessary APIs are enabled</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">i  functions: preparing api directory for uploading...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">i  functions: packaged api (197.62 KB) for uploading</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔  functions: api folder uploaded successfully</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">i  functions: creating Node.js 10 (Beta) function api(europe-west1)...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔  functions[api(europe-west1)]: Successful create operation.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Function URL (api): https://europe-west1-my-cat-in-the-cloud.cloudfunctions.net/api</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✔  Deploy complete!</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>La <strong>Console</strong> de Firebase offre des metrics et du logging pour chaque Function déployée.</p></div></div>
<p>Partant de là, on peut imaginer :</p>
<ul>
<li>Créer de nouveaux controllers/endpoints (e.g. <code>@Post('api/users')</code>, <code>@Get('healthcheck')</code>...)</li>
<li>Présenter une <a href="https://docs.nestjs.com/recipes/swagger" target="_blank" rel="noopener noreferrer">documentation Swagger</a> (e.g. <code>api/&lt;route_choise_pour_le_document_Swagger&gt;</code>)</li>
<li>Ajouter un endpoint pour <a href="https://docs.nestjs.com/graphql/quick-start" target="_blank" rel="noopener noreferrer">GraphQL</a> (e.g. <code>api/graphql</code>)</li>
</ul>
<p>👮 Néanmoins, l'utilisation d'Express et de Nest entraîne nécessairement un surcoût en terme temps de lancement, de temps d'exécution et de mémoire consommée. <strong>Je ne recommande pas</strong> de le faire en production sous prétexte que "c'est possible".   L'article <a href="https://medium.com/lumigo/web-frameworks-implication-on-serverless-cold-start-18ee5eb6c62a" target="_blank" rel="noopener noreferrer">Web Frameworks Implication on Serverless Cold Start Performance in NodeJS</a> traîte bien le sujet, bien qu'il soit concentré sur le <em>Cold start</em>. Pour un fonctionnement optimal, il est recommandé de créer plusieurs Functions très spécialisées (et avec un minimum d'<em>overhead</em>), plutôt qu'une seule offrant une API complète.</p>
<p>À vos <em>use cases</em> 😬 !</p>
<p><em>Credits à <a href="https://twitter.com/jeffdelaney23" target="_blank" rel="noopener noreferrer">@Jeffdelaney23</a> pour l'exposition de Nest en tant que Function</em><br>
<em>Credits à <a href="https://s4m-ur4i.itch.io/" target="_blank" rel="noopener noreferrer">Sam</a> pour le pixel-art de Nuage ☁</em></p>]]></content:encoded>
            <category>nest</category>
            <category>serverless</category>
            <category>firebase</category>
        </item>
        <item>
            <title><![CDATA[Rust et WebAssembly : Wasm everywhere]]></title>
            <link>https://vinceops.me/rust-webassembly-wasm-everywhere</link>
            <guid>https://vinceops.me/rust-webassembly-wasm-everywhere</guid>
            <pubDate>Thu, 21 Nov 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[J'en parlais dans le premier article sur Rust : l'attrait de WebAssembly est l'une des raisons qui m'ont poussé vers ce langage. Dans cet article, j'aborde la compilation de code Rust en un fichier binaire Wasm et la génération du package NPM permettant son exploitation.]]></description>
            <content:encoded><![CDATA[<p>J'en parlais dans le <a href="https://vinceops.me/rust-premiers-retours/">premier article</a> sur Rust : l'attrait de <a href="https://webassembly.org/" target="_blank" rel="noopener noreferrer">WebAssembly</a> est l'une des raisons qui m'ont poussé vers ce langage. Dans cet article, j'aborde la compilation de code Rust en un fichier binaire Wasm et la génération du <em>package</em> NPM permettant son exploitation.</p>
<p>vec Node.js <strong>et</strong> dans le navigateur... <em>Et après je parle <em>beaucoup</em> de WebAssembly 😁</em>.</p>
<img src="https://media.giphy.com/media/PORxKijkF3xw4/giphy.gif" alt="here we go" style="display:block;margin:0 auto 25px auto;width:400px;height:200px">
<blockquote>
<p>🦕 <strong>Deno</strong> ne sera pas abordé dans l'article, mais <a href="https://github.com/denoland/deno/releases/tag/v0.24.0" target="_blank" rel="noopener noreferrer">la version 0.24</a> supporte désormais l'import des modules WebAssembly.</p>
</blockquote>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="dabord-un-peu-de-rust">D'abord, un peu de Rust<a href="https://vinceops.me/rust-webassembly-wasm-everywhere#dabord-un-peu-de-rust" class="hash-link" aria-label="Lien direct vers D'abord, un peu de Rust" title="Lien direct vers D'abord, un peu de Rust">​</a></h2>
<p>Pour changer des exemples <code>sayHello(name)</code> et <code>add(a, b)</code>, on va écrire en Rust une petite <em>lib</em> simpliste qui compte le nombre de jours calendaires séparant deux dates. Par exemple :</p>
<ul>
<li><code>365</code> jours entre Noël 2018 et Noël 2019,</li>
<li><code>0</code> jour entre <code>2019-11-14</code> et <code>2019-11-14T16:58:56.822Z</code></li>
<li><code>29</code> jours entre <code>2012-02-01</code> et <code>2012-03-01</code> (année bisextile)</li>
</ul>
<p>C'est proche de ce que fait <a href="https://momentjs.com/" target="_blank" rel="noopener noreferrer">moment.js</a> avec sa fonction <code>diff</code> (<code>momentA.diff(momentB, 'days')</code>). Pour simplifier le cas, la fonction développée prendra en paramètres des timestamps en millisecondes.</p>
<blockquote>
<p>👮 Chère "Rust Police", ma pratique du langage est toujours très sporadique. Si tu constates une aberration qui t'offusque, n'hésite pas à me DM <a href="https://twitter.com/VinceOPS" target="_blank" rel="noopener noreferrer">sur Twitter</a> 🚨.</p>
</blockquote>
<p>Allez viens, on se crée une <strong>lib</strong> 🚀 ! <em>Je fais l'hypothèse que tu as déjà utilisé Rust et Cargo.</em></p>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">cargo new --lib days-count</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Dans <code>src/lib.rs</code>, on se donne la définition suivante :</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">count_days_between</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">timestamp_ms_a</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">u64</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> timestamp_ms_b</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">u64</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">u64</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>On rapporte chaque timestamp au nombre de jours écoulés depuis le 01/01/1970. Par exemple, pour le 10/01/1970 (timestamp : <code>777600000</code>), on obtient <code>9</code> jours écoulés. Il suffit ensuite de retourner la différence des deux.</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/// Count the number of calendar days between two dates given as</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/// timestamps in milliseconds. Make the assumption that One day is</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/// 86_400_000 milliseconds (leap seconds are ignored).</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">count_days_between</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">timestamp_ms_a</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">u64</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> timestamp_ms_b</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">u64</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">u64</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> days_count_a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> timestamp_ms_a </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3600</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">24</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> days_count_b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> timestamp_ms_b </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3600</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">24</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> days_count_between </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">match</span><span class="token plain"> days_count_a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">checked_sub</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">days_count_b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">difference</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> difference</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">None</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> days_count_b </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> days_count_a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> days_count_between</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Pour le code complet (avec ses tests), c'est <a href="https://gist.github.com/VinceOPS/d8d5cbb34e2cbcd62ac3b8f55bb13c5b" target="_blank" rel="noopener noreferrer">par ici</a>.</p></div></div>
<img src="https://media.giphy.com/media/IspgDOjRHwtbi/giphy.gif" alt="dangerust" style="display:block;margin:0 auto 25px auto;width:340px;height:200px">
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="et-maintenant-du-webassembly">Et maintenant, du WebAssembly<a href="https://vinceops.me/rust-webassembly-wasm-everywhere#et-maintenant-du-webassembly" class="hash-link" aria-label="Lien direct vers Et maintenant, du WebAssembly" title="Lien direct vers Et maintenant, du WebAssembly">​</a></h2>
<p>Chouette 🦉, on a un code Rust qui fonctionne ! Maintenant, il faut le compiler en WebAssembly. C'est <a href="https://rustwasm.github.io/wasm-pack" target="_blank" rel="noopener noreferrer">wasm-pack</a> qui s'en charge, en plus de générer aussi le package NPM contenant le binaire <code>.wasm</code>, notre <code>package.json</code> et les fichiers <code>.js</code> permettant le <em>binding</em> Javascript ↔ Rust 🎆. <em>Merci qui ? Merci <a href="https://rustwasm.github.io/docs/wasm-bindgen/" target="_blank" rel="noopener noreferrer">wasm-bindgen</a></em>.</p>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain"># on ajoute la cible permettant de compiler du Rust en WebAssembly</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">rustup target add wasm32-unknown-unknown</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># et on installe wasm-pack</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Il faut aussi ajouter une dépendance et une <em>lib</em> à notre fichier <code>Cargo.toml</code> :</p>
<div class="language-toml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-toml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain"># [...]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[dependencies]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">wasm-bindgen = "0.2"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[lib]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">crate-type = ["cdylib"]</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Et enfin, ajouter la macro <a href="https://rustwasm.github.io/docs/wasm-bindgen/reference/attributes/index.html" target="_blank" rel="noopener noreferrer"><code>wasm_bindgen</code></a> à notre fonction :</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">use</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">wasm_bindgen</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">prelude</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token attribute attr-name" style="color:#00a4db">#[wasm_bindgen]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">count_days_between</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">timestamp_ms_a</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">u64</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> timestamp_ms_b</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">u64</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">u64</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="dans-nodejs">Dans Node.js<a href="https://vinceops.me/rust-webassembly-wasm-everywhere#dans-nodejs" class="hash-link" aria-label="Lien direct vers Dans Node.js" title="Lien direct vers Dans Node.js">​</a></h3>
<p>On compile ensuite notre <em>lib</em> en exécutant :</p>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">wasm-pack build --release --target nodejs</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<blockquote>
<p>⚙ <code>--release</code> pour la compilation optimisée, <code>--target nodejs</code> pour des bindings adaptés.</p>
</blockquote>
<p>La commande génère le module NPM dans un dossier <code>./pkg</code> que l'on va directement utiliser avec Node.js 10+ 🔥 :</p>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">mkdir nodejs &amp;&amp; cd nodejs</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">yarn init -y # ou : npm init -y</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">yarn add --dev ../pkg # ou : npm i -D ../pkg</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">touch index.js</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Dans le <code>index.js</code> fraîchement créé, on importe le module <code>days-count</code> généré par <code>wasm-pack</code> et on exécute notre fonction <code>count_days_between</code> :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> daysCount </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'days-count'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  daysCount</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">count_days_between</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 01/02/2012</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token known-class-name class-name">BigInt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1330560000000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 01/03/2012</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token known-class-name class-name">BigInt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1328054400000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 29 👍</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>C'est <code>BingInt</code> que l'on utilise comme équivalent au type <code>u64</code> de Rust, puisque <code>number</code> ne peut pas contenir une valeur supérieure à 2<sup>53</sup> - 1 (<code>Number.MAX_SAFE_INTEGER</code>).</p></div></div>
<p>Accessoirement, <code>wasm-pack</code> a <strong>aussi</strong> généré les typedefs (<code>*.d.ts</code>) des <em>bindings</em> JavaScript... On profite donc du typage, de l'autocomplétion et même d'une JSDoc tirée des commentaires Rust (<code>///</code>) 🎉.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Type definitions from Rust" src="https://vinceops.me/assets/images/wasm-bindgen-typedefs-e764bd461742b1d04943d0abdcb89436.jpg" width="948" height="252" class="img_BhpN"></p></div>
<img src="https://media.giphy.com/media/5VKbvrjxpVJCM/giphy.gif" alt="omg" style="display:block;margin:0 auto 25px auto;width:340px;height:270px">
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="dans-le-navigateur">Dans le Navigateur<a href="https://vinceops.me/rust-webassembly-wasm-everywhere#dans-le-navigateur" class="hash-link" aria-label="Lien direct vers Dans le Navigateur" title="Lien direct vers Dans le Navigateur">​</a></h3>
<p><em>La lecture du paragraphe précédent (Node.js) est fortement recommandée.</em></p>
<p>On recompile notre <em>lib</em> en changeant la <code>--target</code> :</p>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">wasm-pack build --release --target bundler</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p><code>bundler</code> est la cible par défaut à ce jour, mais tu peux aussi utiliser <code>web</code> <a href="https://rustwasm.github.io/wasm-pack/book/commands/build.html#target" target="_blank" rel="noopener noreferrer">sous certaines conditions</a>.</p></div></div>
<p>On crée un projet basé sur la template NPM <code>wasm-app</code> :</p>
<div class="language-shell codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-shell codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">mkdir browser &amp;&amp; cd browser</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">npm init wasm-app</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">yarn add --dev ../pkg # ou : npm i -D ../pkg</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">yarn &amp;&amp; yarn build # ou npm install &amp;&amp; npm run build</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Dans <code>index.js</code>, on procède de la même manière qu'avec Node.js :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports operator" style="color:#393A34">*</span><span class="token imports"> </span><span class="token imports keyword module" style="color:#00009f">as</span><span class="token imports"> daysCount</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'days-count'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// pour changer du console.log 🤷</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  daysCount</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">count_days_between</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 01/02/2012</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token known-class-name class-name">BigInt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1330560000000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 01/03/2012</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token known-class-name class-name">BigInt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1328054400000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Un coup de <code>yarn start</code> pour lancer <code>webpack-dev-server</code> et on constate sur <code>http://localhost:8080</code> que "29" est bien ajouté au corps de la page.</p>
<p>Pour les utilisateurs de <a href="https://webpack.js.org/" target="_blank" rel="noopener noreferrer">Webpack</a>, le plugin <a href="https://github.com/wasm-tool/wasm-pack-plugin" target="_blank" rel="noopener noreferrer"><code>wasm-pack-plugin</code></a> est intéressant : il permet l'automatisation du processus que l'on vient de suivre, en <code>import</code>ant directement un projet Rust.</p>
<p>Pour les utilisateurs de <a href="https://parceljs.org/" target="_blank" rel="noopener noreferrer">Parcel</a>, il existe aussi une template NPM dédiée : <a href="https://github.com/rustwasm/rust-parcel-template" target="_blank" rel="noopener noreferrer"><code>rust-parcel</code></a>. Le <a href="https://github.com/rustwasm/rust-parcel-template/blob/master/crate/Cargo.toml" target="_blank" rel="noopener noreferrer"><code>Cargo.toml</code></a> emploie par ailleurs deux <em>crates</em> très utiles : <code>console_error_panic_hook</code>, <code>wee_alloc</code>.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="ce-quil-faut-retenir">Ce qu'il faut retenir<a href="https://vinceops.me/rust-webassembly-wasm-everywhere#ce-quil-faut-retenir" class="hash-link" aria-label="Lien direct vers Ce qu'il faut retenir" title="Lien direct vers Ce qu'il faut retenir">​</a></h2>
<img src="https://media.giphy.com/media/JpdjC3bCBKlA0zt8PP/giphy.gif" alt="so what?" style="display:block;margin:0 auto 25px auto;width:300px;height:180px">
<p>Ok, on a compilé une <em>lib</em> Rust simplissime en WebAssembly, on en a fait un module, on l'a utilisé avec Node.js <strong>et</strong> Webpack. C'est cool, mais ça ne règle <strong>aucun</strong> problème... Ou peut-être que si ?</p>
<p>Les principaux bénéfices à en tirer sont :</p>
<ul>
<li>Des gains <em>très</em> significatifs de <strong>performances</strong> dans l'exécution d'opérations longues et/ou intensives (calcul, compression, multimédia, jeux vidéo...).</li>
<li>La capacité d'utiliser un autre langage que JavaScript dans Node.js et/ou le navigateur. Notamment Rust, C et C++, pour des binaires Wasm optimisés. Si le poids du binaire ou la performance ne sont pas des critères pour votre projet, on peut aussi imaginer que les <em>features</em> du langage utilisé soient un argument suffisant (<a href="https://www.typescriptlang.org/" target="_blank" rel="noopener noreferrer">TypeScript</a> avec <a href="https://github.com/AssemblyScript/assemblyscript" target="_blank" rel="noopener noreferrer">AssemblyScript</a>, <a href="https://github.com/golang/go/wiki/WebAssembly" target="_blank" rel="noopener noreferrer">Go</a>, etc).</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Ce point sera abordé dans un prochain article, mais il est possible d'<strong>utiliser les API Web</strong> depuis le code Rust. Tout est <strong>bien</strong> détaillé dans la <a href="https://rustwasm.github.io/docs/wasm-bindgen/" target="_blank" rel="noopener noreferrer">documentation de wasm-bindgen</a>, dans la partie concernant <a href="https://crates.io/crates/web-sys" target="_blank" rel="noopener noreferrer">web-sys</a> : DOM, Events, fetching, WebGL, WebSockets 🎉...</p><p>C'est aussi vrai avec C et C++ grâce à <a href="https://emscripten.org/" target="_blank" rel="noopener noreferrer">https://emscripten.org</a>.</p></div></div>
<p>Les opportunités apportées par cette technologie sont très prometteuses (et excitantes, <em>ain't they?</em>). Comme beaucoup l'ont dit avant moi, <strong>WebAssembly ne remplacera pas JavaScript</strong>. Et si l'on s'en tient au seul aspect de la performance, même en JavaScript, V8 offre des performances souvent suffisantes pour beaucoup d'applications... Sans parler des outils plus simples à utiliser (et/ou mieux intégrés) en JavaScript <strong>pour le moment</strong> : debugging, code splitting, etc.</p>
<p>Mozilla, Intel, Fastly (créateurs de <a href="https://www.fastly.com/blog/announcing-lucet-fastly-native-webassembly-compiler-runtime" target="_blank" rel="noopener noreferrer">Lucet</a>) et Red Hat ont créé la <a href="https://bytecodealliance.org/" target="_blank" rel="noopener noreferrer">Bytecode Alliance</a>, ayant pour but d'étendre l'existence de WebAssembly au-delà des navigateurs. Plus d'infos sur le <a href="https://blog.mozilla.org/press-fr/2019/11/12/la-nouvelle-alliance-bytecode-apporte-plus-de-securite-dubiquite-et-dinteroperabilite-au-web/" target="_blank" rel="noopener noreferrer">blog de Mozilla</a>... Et concernant <strong>Wasmtime</strong> et les <strong>WebAssembly Interface Types</strong> (WASI), <a href="https://www.youtube.com/watch?v=Qn_4F3foB3Q" target="_blank" rel="noopener noreferrer">cette vidéo de Lin Clark</a> est incontournable 🔥 (et une version plus longue/développée <a href="https://www.youtube.com/watch?v=fh9WXPu0hw8" target="_blank" rel="noopener noreferrer">ici</a>).</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="wasm-everywhere" src="https://vinceops.me/assets/images/wasm-everywhere-9d1631c6eee99492ff92946f68a2c47d.jpg" width="900" height="612" class="img_BhpN"></p></div>
<p>Ah, au fait. J'ai créé un <a href="https://github.com/VinceOPS/rust-wasm-introduction" target="_blank" rel="noopener noreferrer">projet <strong>TypeScript</strong> (💝)</a> exploitant un binaire Wasm avec Node.js <strong>et</strong> Webpack, de la même manière que je l'ai exposé en JavaScript dans cet article.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="bonus---des-ressources-qui-valent-le-détour">Bonus - Des ressources qui valent le détour<a href="https://vinceops.me/rust-webassembly-wasm-everywhere#bonus---des-ressources-qui-valent-le-d%C3%A9tour" class="hash-link" aria-label="Lien direct vers Bonus - Des ressources qui valent le détour" title="Lien direct vers Bonus - Des ressources qui valent le détour">​</a></h3>
<ul>
<li>Diablo 1 en JavaScript (React) et WebAssembly : <a href="https://github.com/d07RiV/diabloweb" target="_blank" rel="noopener noreferrer">diabloweb</a></li>
<li><a href="https://tehnokv.com/posts/pico-to-wasm/" target="_blank" rel="noopener noreferrer">Compiling a face detector written in C to WebAssembly</a></li>
<li>ImageMagick compilé en WebAssembly : <a href="https://github.com/cancerberoSgx/magica/tree/master/magick-wasm" target="_blank" rel="noopener noreferrer">magica</a></li>
<li>Skia, de Google, compilé en WebAssembly : <a href="https://github.com/Zubnix/skia-wasm-port" target="_blank" rel="noopener noreferrer">Zubnix/skia-wasm-port</a></li>
<li>Un émulateur de Game Boy, développé en TypeScript et compilé par <a href="https://github.com/AssemblyScript/assemblyscript" target="_blank" rel="noopener noreferrer">AssemblyScript</a> : <a href="https://github.com/torch2424/wasmboy" target="_blank" rel="noopener noreferrer">wasmboy</a></li>
<li>Qt Framework compatible avec WebAssembly : <a href="https://doc.qt.io/qt-5/wasm.html" target="_blank" rel="noopener noreferrer">Qt 5.13+</a></li>
<li><a href="https://www.youtube.com/watch?v=njt-Qzw0mVY" target="_blank" rel="noopener noreferrer">WebAssembly for Web Developers (Google I/O ’19)</a> et notamment <a href="https://squoosh.app/" target="_blank" rel="noopener noreferrer">Squoosh</a> (<strong>!!</strong>)</li>
</ul>]]></content:encoded>
            <category>rust</category>
            <category>webassembly</category>
            <category>node.js</category>
        </item>
        <item>
            <title><![CDATA[AWS Acceleration Roadshow 2019]]></title>
            <link>https://vinceops.me/aws-acceleration-roadshow</link>
            <guid>https://vinceops.me/aws-acceleration-roadshow</guid>
            <pubDate>Wed, 23 Oct 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Voilà déjà 1 semaine que j'ai assisté à l'AWS Acceleration Roadshow d'Aix en Provence, avec David, aussi lead dev chez Gojob. On a décidé de s'y rendre pour les sujets d'IA/ML, par curiosité technique et par curiosité vis à vis de GCP. En effet, on travaille quotidiennement avec Google Cloud Provider et je n'ai pas utilisé AWS depuis 2017.]]></description>
            <content:encoded><![CDATA[<p>Voilà déjà 1 semaine que j'ai assisté à l'<a href="https://aws.amazon.com/fr/events/acceleration-roadshow-2019/" target="_blank" rel="noopener noreferrer">AWS Acceleration Roadshow</a> d'Aix en Provence, avec David, aussi <em>lead dev</em> chez <a href="https://twitter.com/GojobT" target="_blank" rel="noopener noreferrer">Gojob</a>. On a décidé de s'y rendre pour les sujets d'<strong>IA/ML</strong>, par <strong>curiosité technique</strong> et par <strong>curiosité vis à vis de GCP</strong>. En effet, on travaille quotidiennement avec <em>Google Cloud Provider</em> et je n'ai pas utilisé AWS depuis 2017.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="aws-renaissance" src="https://vinceops.me/assets/images/aws-ar-1-1ca914889d317f6baf5e03339778b03d.jpg" width="900" height="675" class="img_BhpN">
<i style="text-align:center;display:block;margin:10px 0">Hôtel Renaissance : un joli cadre pour cette conf gratuite. Merci aux sponsors, Intel et <a href="https://twitter.com/premaccess" target="_blank" rel="noopener noreferrer">@premaccess</a> !</i></p></div>
<p>Un programme chargé que 4 speakers talentueux ont partagé entre : migration dans le cloud, CI/CD, Intelligence artificielle et <em>Machine Learning</em>, bases de données, IoT, sécurité... Slides disponibles <a href="https://aws.amazon.com/fr/events/acceleration-roadshow-2019/contenu/" target="_blank" rel="noopener noreferrer">ici</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="pourquoi-choisir-de-créer-son-infra-dans-le-cloud-">Pourquoi choisir de créer son infra dans le Cloud ?<a href="https://vinceops.me/aws-acceleration-roadshow#pourquoi-choisir-de-cr%C3%A9er-son-infra-dans-le-cloud-" class="hash-link" aria-label="Lien direct vers Pourquoi choisir de créer son infra dans le Cloud ?" title="Lien direct vers Pourquoi choisir de créer son infra dans le Cloud ?">​</a></h2>
<p>C'est <a href="https://twitter.com/sebsto" target="_blank" rel="noopener noreferrer">Sébastien Stormacq</a>, <em>Developer Advocate</em>, qui ouvre le bal avec "Réussir sa transformation digitale".</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="4 piliers de la transformation" src="https://vinceops.me/assets/images/aws-ar-4-pillar-e9ed06488f2b2004e2ab6269ad70a3ee.jpg" width="1285" height="515" class="img_BhpN"></p></div>
<p>Slides disponibles <a href="https://awsmarketingbucket.s3-eu-west-1.amazonaws.com/2019/Acceleration%20Roadshow/Decks/Pr%C3%A9sentations%20sessions/Session%201%20-%20R%C3%A9ussir%20sa%20transformation%20digitale.pdf" target="_blank" rel="noopener noreferrer"><strong>ici</strong></a></p>
<p>On retiendra, dans les grandes lignes :</p>
<ul>
<li>L'agilité et l'élasticité offertes par le Cloud : disponibilité immédiate des machines, dont le cycle de vie est maîtrisé</li>
<li>Les nouveaux domaines technologiques mis au service des métiers : AI/ML/Data lake, IoT, ...</li>
<li>Le choix de l'emplacement des données entreposées, parmi 22 régions, en fonction de la latence et des aspects légaux</li>
<li>Les certifications de l'infrastructure : PCI DSS, HDS, ...</li>
<li>Le coût total de l'infrastructure (TCO, <em>Total Cost of Ownership</em>) significativement réduit (locaux, équipements, machines, administrateurs, dépannages, planification...)</li>
<li>L'autonomie offertes aux équipes (grâce à l'agilité/elasticité du Cloud)</li>
<li>Le site <a href="https://www.aws.training/" target="_blank" rel="noopener noreferrer">AWS Training</a>, offrant des formations et certifications pour les services AWS.</li>
</ul>
<p>Pour l'anecdote, Amadou Merico présente dans "Migrer ses data-centers dans le cloud", l'<a href="https://aws.amazon.com/fr/snowmobile/" target="_blank" rel="noopener noreferrer">AWS Snowmobile</a>, un container de 14 mètres tiré par un semi-remorque pouvant contenir jusqu'à 100 PB (100000 TB, <em>damn!</em>), spécialement dédié au transfert de données.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="AWS Snowmobile" src="https://vinceops.me/assets/images/snowmobile-d5adbbbfd0368b94fe1ce473e8aabd73.jpg" width="600" height="244" class="img_BhpN"></p></div>
<p>Il a aussi assuré une belle présentation sur les différentes base de données AWS, <a href="https://awsmarketingbucket.s3-eu-west-1.amazonaws.com/2019/Acceleration%20Roadshow/Decks/Pr%C3%A9sentations%20sessions/Session%205%20-%20Comment%20choisir%20sa%20base%20de%20donn%C3%A9es.pdf" target="_blank" rel="noopener noreferrer">Comment choisir sa base de données</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="les-services-exploitant-ia-et-ml">Les services exploitant IA et ML<a href="https://vinceops.me/aws-acceleration-roadshow#les-services-exploitant-ia-et-ml" class="hash-link" aria-label="Lien direct vers Les services exploitant IA et ML" title="Lien direct vers Les services exploitant IA et ML">​</a></h2>
<p>Les intervenants n'ont évidemment pas présenté les 165 services offerts par AWS, mais parmi ceux utilisant IA et ML, on retiendra :</p>
<ul>
<li><a href="https://aws.amazon.com/fr/rekognition/" target="_blank" rel="noopener noreferrer">AWS Rekognition</a> : Analyse intelligente de photos et de vidéos permettant l'identification de personnes, textes, objets... Ainsi qu'un redoutable outil de reconnaissance faciale.</li>
<li><a href="https://aws.amazon.com/fr/polly/" target="_blank" rel="noopener noreferrer">AWS Polly</a> : Synthèse vocale intelligente, capable (grâce au <em>Machine learning</em>) de lire un texte en utilisant différentes intonations, en s'adaptant aux prononciations d'une langue spécifique.</li>
<li><a href="https://aws.amazon.com/fr/textract/" target="_blank" rel="noopener noreferrer">AWS Textract</a> : Extraction de texte depuis des documents scannés, avec la capacité d'identifier des zones spécifiques (champs de formulaire, etc).</li>
<li><a href="https://aws.amazon.com/fr/comprehend/" target="_blank" rel="noopener noreferrer">AWS Comprehend</a> : Traitement de langue naturelle permettant de déduire d'un texte les organismes cités, le sentiment général (positif, négatif, neutre...), la langue utilisée, etc.</li>
<li><a href="https://aws.amazon.com/fr/translate/" target="_blank" rel="noopener noreferrer">AWS Translate</a> : Traduction sans langue intermédiaire (e.g. Français =&gt; Japonais directement, plutôt que Français =&gt; Anglais, puis Anglais =&gt; Japonais) basée sur des modèles de <em>deep learning</em>.</li>
<li><a href="https://aws.amazon.com/fr/lex/" target="_blank" rel="noopener noreferrer">Amazon Lex</a> : Création d'interfaces de type <em>chatbot</em> (basé sur les mêmes modèles d'apprentissage qu'Alexa).</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="et-face-à-google-cloud-">Et face à Google Cloud ?<a href="https://vinceops.me/aws-acceleration-roadshow#et-face-%C3%A0-google-cloud-" class="hash-link" aria-label="Lien direct vers Et face à Google Cloud ?" title="Lien direct vers Et face à Google Cloud ?">​</a></h2>
<p>Si la majorité des plateformes Cloud offrent les mêmes services fondamentaux, tels qu'<a href="https://aws.amazon.com/fr/ec2/" target="_blank" rel="noopener noreferrer">EC2</a>, <a href="https://aws.amazon.com/fr/rds/" target="_blank" rel="noopener noreferrer">RDS</a> et <a href="https://aws.amazon.com/fr/s3/" target="_blank" rel="noopener noreferrer">S3</a> (respectivement, dans <a href="https://cloud.google.com/products" target="_blank" rel="noopener noreferrer">Google Cloud</a> : <a href="https://cloud.google.com/compute" target="_blank" rel="noopener noreferrer">Compute Engine</a>, <a href="https://cloud.google.com/sql/" target="_blank" rel="noopener noreferrer">Cloud SQL</a> et <a href="https://cloud.google.com/storage" target="_blank" rel="noopener noreferrer">Cloud Storage</a>), certains services n'ont pas encore d'égal chez leurs rivaux.</p>
<p>Un comparatif (certes proposé par Google 😁) <a href="https://cloud.google.com/docs/compare/aws" target="_blank" rel="noopener noreferrer">est disponible ici</a>. Celui-ci n'est pas exhaustif : en effet, nul équivalent à <a href="https://aws.amazon.com/fr/neptune/" target="_blank" rel="noopener noreferrer">AWS Neptune</a>, BDD orientée Graphe. Pas plus qu'à <a href="https://aws.amazon.com/fr/timestream/" target="_blank" rel="noopener noreferrer">AWS Timestream</a>, BDD chronologique (oui, on parle de besoins de niches 🤷). <strong>En revanche</strong>, Google Cloud offre une alternative à tous les services suscités (IA/ML). Et aussi, <a href="https://www.elastic.co/fr/blog/elasticsearch-service-now-available-on-google-cloud-marketplace" target="_blank" rel="noopener noreferrer"><strong>depuis hier</strong></a>, des instances <em>managées</em> d'Elasticsearch (comme <a href="https://aws.amazon.com/fr/elasticsearch-service/" target="_blank" rel="noopener noreferrer">AWS Elasticsearch Service</a>).</p>
<img src="https://media.giphy.com/media/Na33dsU2umStO/giphy.gif" alt="omg-yes" style="display:block;margin:0 auto 25px auto;width:230px;height:200px">
<p>Mais l'article n'a pas pour but de comparer les plateformes : cela mériterait un livre entier réédité tous les 6 mois, tant les facteurs à prendre en compte sont nombreux et sujets au changement. Richesse fonctionnelle des services, facilité d'utilisation, qualité des documentations, tarifications, <a href="https://fr.wikipedia.org/wiki/Service-level_agreement" target="_blank" rel="noopener noreferrer">SLA</a>, etc.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="en-conclusion">En conclusion<a href="https://vinceops.me/aws-acceleration-roadshow#en-conclusion" class="hash-link" aria-label="Lien direct vers En conclusion" title="Lien direct vers En conclusion">​</a></h2>
<p>Les présentations étaient d'une grande qualité et méritent le coup d'œil (slides disponibles <a href="https://aws.amazon.com/fr/events/acceleration-roadshow-2019/contenu/" target="_blank" rel="noopener noreferrer"><strong>ici</strong></a>) si vous n'avez pas encore franchi le pas du Cloud, pour le déploiement d'applications comme pour l'utilisation de services : les premières utilisations (en heures, en stockage...) des services AWS sont souvent offertes.</p>
<p><em>Premaccess organisera aussi un récap' du AWS re<!-- -->:Invent<!-- --> 2019 à Marseille, le 19 décembre.</em></p>]]></content:encoded>
            <category>aws</category>
            <category>devops</category>
        </item>
        <item>
            <title><![CDATA[Git : Astuces et productivité #2]]></title>
            <link>https://vinceops.me/git-astuces-productivite-2</link>
            <guid>https://vinceops.me/git-astuces-productivite-2</guid>
            <pubDate>Wed, 18 Sep 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Dans ce second article de la série, je parle d'alias, de git add -p (patch) et de l'intégration de git dans VS Code.]]></description>
            <content:encoded><![CDATA[<p>Dans ce second article de la série, je parle d'alias, de <code>git add -p</code> (patch) et de l'intégration de <a href="https://git-scm.com/" target="_blank" rel="noopener noreferrer">git</a> dans <a href="https://code.visualstudio.com/" target="_blank" rel="noopener noreferrer">VS Code</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="alias-de-commandes">Alias de commandes<a href="https://vinceops.me/git-astuces-productivite-2#alias-de-commandes" class="hash-link" aria-label="Lien direct vers Alias de commandes" title="Lien direct vers Alias de commandes">​</a></h2>
<p>Ce n'est pas grand chose, car on parle de quelques secondes grattées par-ci par-là. Mais grattées jusqu'à plusieurs dizaines de fois par jour, ça compte comme de la productivité 😏 !</p>
<img src="https://media.giphy.com/media/5isTFajX8zbcA/giphy.gif" alt="cat-scratching-oklm" style="display:block;margin:0 auto 25px auto;width:230px;height:200px">
<p>Au quotidien, j'utilise le Z shell aka <strong>zsh</strong>, avec <a href="https://ohmyz.sh/" target="_blank" rel="noopener noreferrer">oh-my-zsh</a>. L'idée n'est pas de vous présenter mon thème ou mon <em>setup</em> (Debian 9 avec <a href="https://i3wm.org/" target="_blank" rel="noopener noreferrer">i3wm</a>), mais de partager quelques alias <strong>très</strong> pratiques importés par le <strong>plugin git</strong> de oh-my-zsh. Il est activé par défaut. Vous pouvez aussi les récupérer directement <a href="https://github.com/robbyrussell/oh-my-zsh/blob/master/plugins/git/git.plugin.zsh" target="_blank" rel="noopener noreferrer">ici</a> et les intégrer à votre fichier <em>run commands</em> (<code>.bashrc</code>, <code>.zshrc</code>...).</p>
<p>Parmi ceux que j'utilise souvent :</p>
<ul>
<li><code>g</code> : <code>git</code></li>
<li><code>ga</code> : <code>git add</code> (<code>gaa</code> pour <code>git add --all</code>)</li>
<li><code>gcb</code> : <code>git checkout -b</code></li>
<li><code>gcm</code> : <code>git checkout master</code></li>
<li><code>gc</code> : <code>git commit</code></li>
<li><code>gcn!</code> : <code>git commit --no-edit --amend</code></li>
<li><code>gd</code> : <code>git diff</code></li>
<li><code>ggpur</code> : <code>git pull --rebase origin &lt;current_branch&gt;</code></li>
<li><code>gfa</code> : <code>git fetch --all --prune</code></li>
<li><code>gpf</code> : <code>git push --force--with-lease</code> (<code>gpf!</code> pour <code>--force</code>)</li>
<li><code>grb</code> : <code>git rebase</code> (<code>grba</code> pour <code>--abort</code>, <code>grbc</code> pour <code>--continue</code>, <code>grbi</code> pour <code>-i</code>) 💖</li>
<li><code>groh</code> : <code>git reset --hard origin/&lt;current_branch&gt;</code></li>
<li><code>gst</code> : <code>git status</code></li>
</ul>
<p>Évidemment, on les mémorise à force de réutilisation.</p>
<p>Au passage, oh-my-zsh a aussi un <strong>plugin yarn</strong> avec <a href="https://github.com/robbyrussell/oh-my-zsh/blob/master/plugins/yarn/yarn.plugin.zsh" target="_blank" rel="noopener noreferrer">quelques alias</a> tous aussi efficaces :</p>
<ul>
<li><code>y</code> : <code>yarn</code></li>
<li><code>ya</code> : <code>yarn add</code> (<code>yad</code> pour <code>--dev</code>)</li>
<li><code>yb</code> : <code>yarn build</code></li>
<li><code>yrm</code> : <code>yarn remove</code></li>
<li><code>yst</code> : <code>yarn start</code></li>
<li><code>yt</code> : <code>yarn test</code> 🔥</li>
</ul>
<hr>
<p>Et maintenant, parlons de trucs utiles !</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="indexation-partielle-avec-git-add--p">Indexation partielle avec <code>git add -p</code><a href="https://vinceops.me/git-astuces-productivite-2#indexation-partielle-avec-git-add--p" class="hash-link" aria-label="Lien direct vers indexation-partielle-avec-git-add--p" title="Lien direct vers indexation-partielle-avec-git-add--p">​</a></h2>
<p>C'est une option présentée dans le mode interactif (<code>-i</code>) de <code>git add</code> (cf. le "<a href="https://git-scm.com/book/en/v2" target="_blank" rel="noopener noreferrer">Book</a>" 📚 !) qui permet l'indexation (<em>staging</em>) <strong>partielle</strong> d'un fichier.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="exemple-true-story">Exemple <em>"True story"</em><a href="https://vinceops.me/git-astuces-productivite-2#exemple-true-story" class="hash-link" aria-label="Lien direct vers exemple-true-story" title="Lien direct vers exemple-true-story">​</a></h3>
<p>Vous travaillez sur une évolution de votre produit en suivant votre cycle <em>Red/Green/Refacto</em> habituel. Et là, c'est le drame. Vous trouvez un bout de code <strong>"legacy"</strong> (<em>"oh my god, he said the L word! 😱"</em>) que vous savez refacto par cœur.</p>
<blockquote>
<p>- 👼 : "Fais d'abord passer ton test. Cette refacto peut attendre."<br>
<!-- -->- 👿 : "C'est quoi ce code ?! Allez nettoie, y en a pour 20 secondes !"</p>
</blockquote>
<p>Quoi qu'il arrive, le fichier va subir deux modifications, une pour l'évolution, une pour le <em>refactoring</em>.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="REFACTOR ME" src="https://vinceops.me/assets/images/depressed-developer-refactoring-1ab97f1325dddabf1cac76b46c12edff.png" width="1276" height="623" class="img_BhpN"></p></div>
<p>Plusieurs options s'offrent à vous, dont :</p>
<ul>
<li>Pousser tous les changements dans un seul et même commit (<strong>DON'T</strong>, les <a href="https://vinceops.me/git-astuces-productivite-1">commits atomiques</a>, tout ça...)</li>
<li>Remiser (<code>git stash</code>) les changements, faire et enregistrer le <em>refactoring</em> dans un <em>commit</em> dédié, reprendre les changements remisés (<code>git stash pop</code>)</li>
<li>Avoir recours à <strong><code>git add -p</code></strong> pour indéxer et <em>commit</em> <strong>seulement</strong> le <em>refactoring</em> 🤷</li>
</ul>
<p><em>Pour traiter un cas simple, les exemples qui suivent montrent l'ajout d'un test unitaire 🙄.</em></p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="via-la-cli">Via la CLI<a href="https://vinceops.me/git-astuces-productivite-2#via-la-cli" class="hash-link" aria-label="Lien direct vers Via la CLI" title="Lien direct vers Via la CLI">​</a></h3>
<p>Vous devez faire évoluer le code d'un collègue fan de <em>retrospective testing</em> (ou "j'écris mes tests une fois que je crois avoir fini") et vous constatez qu'un cas d'usage n'a pas été couvert. Vous écrivez le test qui va bien et décidez de l'indexer immédiatement :</p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">$ git add -p</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">diff --git a/src/input-parsing/input-reporting.service.spec.ts b/src/input-parsing/input-reporting.service.spec.ts</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">index 10e5cc8..b9cf134 100644</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--- a/src/input-parsing/input-reporting.service.spec.ts</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+++ b/src/input-parsing/input-reporting.service.spec.ts</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Pour chaque fichier modifié, ici <code>src/input-parsing/input-reporting.service.spec.ts</code>, le terminal affiche les changements indexables :</p>
<div class="language-diff codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-diff codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">@@ -10,6 +10,11 @@ describe('InputReportingService', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     const separatorRow = `🤸;🏋;🚴;🚣;🏊;`;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     const emptyRow = `;;;;;`;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+    it('writes any new file starting with a "separator"', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+      const result = service.generateSynthesis([]);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+      expect(result.startsWith(separatorRow)).toEqual(true);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+    });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     it('adds an empty row after a new entry', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       const result = service.generateSynthesis([]);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       expect(result.startsWith(separatorRow)).toEqual(true);</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Voici du <em>bullshit</em> code : totalement factice, à usage purement démonstratif. <em>Et oui Jamy !</em></p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">Stage this hunk [y,n,q,a,d,e,?]? ?</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Différentes options s'offrent à vous pour le traitement de ce "<em>hunk</em>" (morceau) :</p>
<ul>
<li>y - Indexer le morceau présenté</li>
<li>n - Ignorer ce morceau et passer au suivant</li>
<li>q - Abandonner / quitter ce mode interactif</li>
<li>a - Indexer ce morceau et tous ceux du fichier courant</li>
<li>d - Ignorer ce morceau et passer au fichier suivant</li>
<li>e - Modifier manuellement le morceau courant (pour les ajouts !)</li>
</ul>
<p>Sur des plus gros <em>hunks</em>, quelques autres options sont disponibles :</p>
<ul>
<li>g - Sélectionner un morceau dans le fichier courant</li>
<li>/ - Chercher un morceau en utilisant une Regex</li>
<li>s - Proposer à nouveau ces options avec un morceau plus petit (découpé en plusieurs morceaux)</li>
<li>j - Marquer ce morceau comme "indécis" et sélectionner le prochain morceau indécis</li>
<li>J - Marquer ce morceau comme "indécis" et sélectionner le morceau suivant</li>
</ul>
<p>Dans le cas d'un fichier ayant été modifié à deux endroits, on peut donc <strong>indexer un premier morceau</strong>, enregistrer un <strong>commit</strong>, puis à nouveau <strong>indexer le deuxième morceau</strong> et enregistrer un autre <strong>commit</strong>.<br>
<!-- -->Comme argumenté dans le <a href="http://localhost:8000/git-astuces-productivite-1" target="_blank" rel="noopener noreferrer">premier article de cette série</a> : un historique plus clair, un <em>versionning</em> plus granulaire et des <em>reviewers</em> plus heureux !</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="dans-vs-code">Dans VS Code<a href="https://vinceops.me/git-astuces-productivite-2#dans-vs-code" class="hash-link" aria-label="Lien direct vers Dans VS Code" title="Lien direct vers Dans VS Code">​</a></h3>
<p>L'éditeur offre une interface très pratique pour l'indexation de <em>hunks</em> :</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Stage a Hunk with VS Code" src="https://vinceops.me/assets/images/git_add_patch_vscode-e2a6b2cd3a556d3ee173496aa1c42167.png" width="959" height="354" class="img_BhpN"></p></div>
<p>En ouvrant un fichier depuis l'onglet <strong>Source Control</strong>, on peut sélectionner des morceaux (changés, ajoutés, ou supprimés) et les indexer, ou les désindexer. Je préfère cette approche visuelle, que je trouve plus efficace pour les besoins les plus communs. C'est d'ailleurs une habitude bien ancrée : j'alterne en permanence entre les terminaux et l'éditeur, en fonction de ce qui me proccure la meilleure vélocité 🚀.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="vs-code--git--">VS Code + Git = 💕<a href="https://vinceops.me/git-astuces-productivite-2#vs-code--git--" class="hash-link" aria-label="Lien direct vers VS Code + Git = 💕" title="Lien direct vers VS Code + Git = 💕">​</a></h2>
<p>En ce qui concerne VS Code, il y a quelques "trucs" qu'il faut absolument connaître :</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="éditeur">Éditeur<a href="https://vinceops.me/git-astuces-productivite-2#%C3%A9diteur" class="hash-link" aria-label="Lien direct vers Éditeur" title="Lien direct vers Éditeur">​</a></h3>
<p>Vous pouvez définir VS Code comme éditeur pour git.<br>
<!-- -->En effet, après avoir vérifié que <code>code</code> était disponible dans votre <code>PATH</code>, lancez la commande <code>git config --global core.editor "code --wait"</code>.<br>
<!-- -->La modification de la configuration Git, les rebasages intéractifs, etc, peuvent ainsi être effectués via VS Code :</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="VSCode comme Éditeur git" src="https://vinceops.me/assets/images/vscode_git_editor-cdc05386be426682ac05dd582fdeaea4.jpg" width="625" height="145" class="img_BhpN"></p></div>
<p>Ici, il est question d'être efficace : je préfère me retrouver sur VSCode que sur un éditeur <em><code>vi</code>-like</em> pour ce genre d'opérations. C'est personnel.</p>
<img src="https://media.giphy.com/media/RDmVxCrAp7kti/giphy.gif" style="display:block;margin:0 auto 25px auto;width:250px;height:250px">
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="gitlens">GitLens<a href="https://vinceops.me/git-astuces-productivite-2#gitlens" class="hash-link" aria-label="Lien direct vers GitLens" title="Lien direct vers GitLens">​</a></h3>
<p>Extension absolument incontournable de VS Code, <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens" target="_blank" rel="noopener noreferrer">GitLens</a> offre entre autres :</p>
<ul>
<li>L'affichage du <code>git blame</code> (auteur/date de la dernière modification) de la ligne courante</li>
</ul>
<div class="language-typescript{1} codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript{1} codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">const weekMoment = moment() // VinceOPS, a month ago • feat: a week as a period</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  .set("week", weekNumber)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  .set("year", year);</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ul>
<li>La comparaison, pour le fichier courant, de ses révisions N et N-1 (puis N-1 et N-2, et ainsi de suite)...</li>
</ul>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="VSCode &amp;amp; GitLens - Diff" src="https://vinceops.me/assets/images/vscode_gitlens_diff-3b8674eb5e5a089316bb17d46414c7ab.jpg" width="1044" height="224" class="img_BhpN"></p></div>
<p>Au quotidien, ce sont ces deux premières fonctionnalités qui me sont les plus utiles.</p>
<ul>
<li>Dans un onglet dédié de la <em>side bar</em> :<!-- -->
<ul>
<li>L'historique des commits de la branche courante, avec affichage (<code>diff</code>) de chaque modification</li>
<li>La navigation dans les différentes branches du dépôt</li>
<li>La liste des différentes remises (<em>stash</em>) du dépôt</li>
<li>La recherche de commits par auteur, message, SHA1, fichiers modifiés...</li>
<li>Plein de trucs que l'on peut faire plus vite depuis un terminal (créer/supprimer/<em>merge</em> une branche, etc)</li>
</ul>
</li>
</ul>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="VSCode &amp;amp; GitLens - Diff" src="https://vinceops.me/assets/images/vscode_gitlens_sidebar-ed9562a90b5ec2c50b8f95bff429f3bd.jpg" width="554" height="982" class="img_BhpN"></p></div>
<p>L'historique des commits d'une branche est très utile pour de la <strong>code review</strong>, ou pour se remémorer ses derniers travaux 😁. Consultez la <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens" target="_blank" rel="noopener noreferrer">liste exhaustive</a> des fonctionnalités, vous dénicherez peut-être <strong>votre</strong> pépite.</p>
<p>C'est tout pour ce second article. <code>#teaser</code> Dans le prochain, on parlera de <code>amend</code>, de <code>rebase</code> (avec <code>squash</code> et <code>fixup</code>), ainsi que du <code>reflog</code>.</p>]]></content:encoded>
            <category>git</category>
            <category>productivité</category>
            <category>vs code</category>
        </item>
        <item>
            <title><![CDATA[Rust : Premiers retours sur le langage]]></title>
            <link>https://vinceops.me/rust-premiers-retours</link>
            <guid>https://vinceops.me/rust-premiers-retours</guid>
            <pubDate>Mon, 26 Aug 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Quand je n'écris pas en TypeScript, je m'intéresse à Rust, langage de programmation système au typage fort et statique créé par Mozilla.]]></description>
            <content:encoded><![CDATA[<p>Quand je n'écris pas en <a href="https://www.typescriptlang.org/" target="_blank" rel="noopener noreferrer">TypeScript</a>, je m'intéresse à <a href="https://www.rust-lang.org/" target="_blank" rel="noopener noreferrer"><strong>Rust</strong></a>, langage de programmation système au typage fort et statique créé par <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Rust" target="_blank" rel="noopener noreferrer">Mozilla</a>.</p>
<p>ntre autres, par nostalgie pour la prog. système <strong>et</strong> surtout pour son interopérabilité <a href="https://www.rust-lang.org/what/wasm" target="_blank" rel="noopener noreferrer">optimisée</a> avec <a href="https://rustwasm.github.io/docs/book/" target="_blank" rel="noopener noreferrer"><strong>WebAssembly</strong></a>. À ce sujet, j'ai d'abord étudié <a href="https://github.com/AssemblyScript/assemblyscript" target="_blank" rel="noopener noreferrer">AssemblyScript</a> (compilation TypeScript vers WebAssembly) mais celui-ci n'est pas une option viable <a href="https://www.assemblyscript.org/frequently-asked-questions.html#how-does-assemblyscript-compare-relate-to-c-rust" target="_blank" rel="noopener noreferrer">pour le moment</a> (<em>"AssemblyScript differs in that it is new and tries another approach. It's not as mature as Emscripten and Rust [...]"</em>).</p>
<p><strong>Dans cet article, je partage <em>quelques</em> éléments notables et mes premières impressions sur Rust et son écosystème</strong>, en tant que développeur travaillant avec Node.js et TypeScript depuis plus de 4 ans (bien qu'ayant aussi travaillé avec PHP, C, Java, C# et d'autres).</p>
<p><strong>TL;DR</strong>: Si vous connaissez déjà bien Rust, vous n'apprendrez probablement rien dans cet article. Je ne suis moi-même pas encore un expert du sujet.</p>
<blockquote>
<p>👮 <strong>Disclaimer</strong> : Un minimum de connaissances en POO et en allocation mémoire est requis pour certains passages de l'article.</p>
</blockquote>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="installation-et-hello-world">Installation et "Hello World"<a href="https://vinceops.me/rust-premiers-retours#installation-et-hello-world" class="hash-link" aria-label="Lien direct vers Installation et &quot;Hello World&quot;" title="Lien direct vers Installation et &quot;Hello World&quot;">​</a></h2>
<p>L'installation est très simple :</p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">curl https://sh.rustup.rs -sSf | sh</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Pour une mise à jour : `rustup update`</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Vous disposez ensuite de <a href="https://doc.rust-lang.org/cargo/" target="_blank" rel="noopener noreferrer">Cargo</a>, le <strong>gestionnaire de <a href="https://crates.io/" target="_blank" rel="noopener noreferrer">paquets</a> officiel</strong> du langage (<code>cargo &lt;update | search | ...&gt;</code>).<br>
<!-- -->Il permet aussi de :</p>
<ul>
<li>Créer un projet : <code>cargo new</code></li>
<li>Compiler le projet : <code>cargo build</code></li>
<li>Générer la documentation du projet : <code>cargo doc</code></li>
<li>Lancer l'exécutable du projet : <code>cargo run</code></li>
<li>Lancer les tests : <code>cargo test</code></li>
<li><em>Linter</em> le code : <code>cargo clippy</code> (<a href="https://github.com/rust-lang/rust-clippy" target="_blank" rel="noopener noreferrer">clippy</a>)</li>
<li>Formatter le code <code>cargo fmt</code> (<a href="https://github.com/rust-lang/rustfmt" target="_blank" rel="noopener noreferrer">rustfmt</a>)</li>
<li><a href="https://crates.io/search?q=cargo" target="_blank" rel="noopener noreferrer">etc</a>, etc</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>La plupart de ces tâches sont exécutées par d'autres programmes. Cargo est leur interface commune.</p></div></div>
<p>On crée un nouveau projet :</p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">cargo new my_project</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le projet ainsi généré contient : un dépôt <strong>git</strong> et son <code>.gitignore</code>, <code>Cargo.toml</code> (équivalent au <code>package.json</code>), <code>Cargo.lock</code> (équivalent au <code>package-lock.json</code> / <code>yarn.lock</code>), ainsi qu'un premier <em>Hello World</em> dans <code>src/main.rs</code>.</p>
<p>Et c'est <em>déjà</em> prêt ! L'installation est simplissime et fournit un outil standard effectuant toutes les tâches usuelles du développement : 🎉. Quant au <strong>Hello world</strong>, on le compile et l'exécute avec <code>cargo run</code> :</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// src/main.rs</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Hello world"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-language-none codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-language-none codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">$ cargo run</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Finished dev [unoptimized + debuginfo] target(s) in 0.06s</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     Running `target/debug/my_project`</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Hello world</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="remarques-et-impressions">Remarques et impressions<a href="https://vinceops.me/rust-premiers-retours#remarques-et-impressions" class="hash-link" aria-label="Lien direct vers Remarques et impressions" title="Lien direct vers Remarques et impressions">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="documentations">Documentations<a href="https://vinceops.me/rust-premiers-retours#documentations" class="hash-link" aria-label="Lien direct vers Documentations" title="Lien direct vers Documentations">​</a></h3>
<p>La <a href="https://doc.rust-lang.org/stable/book" target="_blank" rel="noopener noreferrer">documentation du langage</a> ("The Book") est très bien construite, avec un niveau de détails parfaitement jaugé. On peut y accéder, même hors-ligne, en exécutant la commande <code>rustup doc --book</code>.</p>
<p>J'en profite pour citer l'excellent <a href="https://doc.rust-lang.org/rust-by-example" target="_blank" rel="noopener noreferrer">Rust by Example</a> et les <a href="https://rust-lang-nursery.github.io/api-guidelines/about.html" target="_blank" rel="noopener noreferrer">Rust API Guidelines</a>, sans oublier <a href="https://doc.rust-lang.org/reference" target="_blank" rel="noopener noreferrer">The Rust Reference</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="intégration-avec-vs-code">Intégration avec VS Code<a href="https://vinceops.me/rust-premiers-retours#int%C3%A9gration-avec-vs-code" class="hash-link" aria-label="Lien direct vers Intégration avec VS Code" title="Lien direct vers Intégration avec VS Code">​</a></h3>
<p>L'équipe en charge du <a href="https://github.com/rust-lang/rls" target="_blank" rel="noopener noreferrer">Rust Language Server</a> (comparable au <a href="https://github.com/Microsoft/TypeScript/wiki/Standalone-Server-(tsserver)" target="_blank" rel="noopener noreferrer">TSserver</a>) a développé un client VS Code : le plugin officiel <a href="https://marketplace.visualstudio.com/items?itemName=rust-lang.rust" target="_blank" rel="noopener noreferrer">Rust</a>. Il apporte une intégration complète, quoiqu'encore un peu lente : coloration, autocompletion, documentation, lint, etc.</p>
<p>Ces plugins, bien qu'optionnels, peuvent s'avérer utiles :</p>
<ul>
<li><a href="https://marketplace.visualstudio.com/items?itemName=bungcip.better-toml" target="_blank" rel="noopener noreferrer">Better TOML</a> pour un meilleur support des fichiers TOML (<code>Cargo.toml</code>).</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=serayuzgur.crates" target="_blank" rel="noopener noreferrer">crates</a>, qui fournit une interface pour la gestion des versions des crates dans <code>Cargo.toml</code>.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="cargo-et-les-crates">Cargo et les Crates<a href="https://vinceops.me/rust-premiers-retours#cargo-et-les-crates" class="hash-link" aria-label="Lien direct vers Cargo et les Crates" title="Lien direct vers Cargo et les Crates">​</a></h3>
<p>Les packages, en Rust, sont composés d'un à plusieurs <strong>crates</strong> (bibliothèque ou exécutable). Le registre officiel, <a href="https://crates.io/" target="_blank" rel="noopener noreferrer">crates.io</a> en contient à ce jour plus de 29 000, dont certains fournis par l'équipe officielle, comme <a href="https://crates.io/crates/rand" target="_blank" rel="noopener noreferrer">rand</a>, <a href="https://crates.io/crates/time" target="_blank" rel="noopener noreferrer">time</a> et <a href="https://crates.io/users/alexcrichton" target="_blank" rel="noopener noreferrer">beaucoup</a> d'<a href="https://crates.io/teams/github:rust-lang-nursery:libs" target="_blank" rel="noopener noreferrer">autres</a>.</p>
<p>Pour ajouter une dépendance au projet, on insère (manuellement) son nom et sa version aux <code>[dependencies]</code> de <code>Cargo.toml</code> :</p>
<div class="language-toml codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-toml codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">[dependencies]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">rand = "0.7.0"</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Chaque paquet est ensuite installé en exécutant <code>cargo build</code>, qui met aussi à jour <code>Cargo.lock</code>.</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Pour installer une dépendance en passant par la CLI, il est nécessaire d'utiliser le <a href="https://github.com/killercup/cargo-edit" target="_blank" rel="noopener noreferrer">crate <code>cargo-edit</code></a>. Son intégration officielle est supposément <a href="https://github.com/rust-lang/cargo/issues/5586" target="_blank" rel="noopener noreferrer">en cours</a>.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="quelques-éléments-notables-du-langage">Quelques éléments notables du langage<a href="https://vinceops.me/rust-premiers-retours#quelques-%C3%A9l%C3%A9ments-notables-du-langage" class="hash-link" aria-label="Lien direct vers Quelques éléments notables du langage" title="Lien direct vers Quelques éléments notables du langage">​</a></h3>
<p>Comme annoncé en introduction, Rust est fortement <strong>et</strong> statiquement typé. Il offre une inférence (déduction) de typage <a href="https://doc.rust-lang.org/stable/rust-by-example/types/inference.html" target="_blank" rel="noopener noreferrer">très efficace</a>. Les trois axes mis en avant par ses créateurs sont la <strong>Performance</strong> (rapide, gestion de la mémoire efficace, absence de <em>garbage collector</em>...), la <strong>Fiabilité</strong> (système de typage, utilisation de la mémoire...) et la <strong>Productivité</strong> (excellente documentation, compilateur très expressif, outils optimaux...).</p>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="immutabilité">Immutabilité<a href="https://vinceops.me/rust-premiers-retours#immutabilit%C3%A9" class="hash-link" aria-label="Lien direct vers Immutabilité" title="Lien direct vers Immutabilité">​</a></h4>
<p>Les variables sont <strong>immutables par défaut</strong>. On utilise le mot clé <code>mut</code> si l'on souhaite déclarer une variable mutable. La convention de nommage est le <code>snake_case</code> 🐍.</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// type "i32" déduit pour les deux variables</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> immutable_x </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> mutable_x </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">immutable_x </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// err. "Cannot assign twice to immutable variable</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">mutable_x </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// OK</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="le-compilateur">Le compilateur<a href="https://vinceops.me/rust-premiers-retours#le-compilateur" class="hash-link" aria-label="Lien direct vers Le compilateur" title="Lien direct vers Le compilateur">​</a></h4>
<p>Deux mots sur le compilateur, <a href="https://rust-lang.github.io/rustc-guide" target="_blank" rel="noopener noreferrer">rustc</a> :</p>
<ul>
<li>Il repose sur <a href="https://llvm.org/" target="_blank" rel="noopener noreferrer">LLVM</a> pour la génération du code machine</li>
<li>L'expressivité des messages d'erreur est excellente.</li>
</ul>
<p><em>Exemple ici (messages copiés en commentaire), lorsqu'on tente de ré-affecter une variable non mutable</em></p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> x </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// ❌ error[E0384]: cannot assign twice to immutable variable `x`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token comment" style="color:#999988;font-style:italic">// -</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token comment" style="color:#999988;font-style:italic">// |</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token comment" style="color:#999988;font-style:italic">// first assignment to `x`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token comment" style="color:#999988;font-style:italic">// help: make this binding mutable: `mut x`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"The value of x is: {}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> x</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    x </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">6</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ^^^^^ cannot assign twice to immutable variable</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img src="https://media.giphy.com/media/BzkNVs4orw81xHOKHA/giphy.gif" alt="thanks" style="width:300px;margin:20px auto;display:block">
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="types-et-instances-méthodes-visibilité">Types et Instances, Méthodes, Visibilité...<a href="https://vinceops.me/rust-premiers-retours#types-et-instances-m%C3%A9thodes-visibilit%C3%A9" class="hash-link" aria-label="Lien direct vers Types et Instances, Méthodes, Visibilité..." title="Lien direct vers Types et Instances, Méthodes, Visibilité...">​</a></h4>
<p>Dans les types du langage, on retrouve les :</p>
<ul>
<li>Booléens (<code>bool</code>, 1 octet)</li>
<li>Entiers signés <code>iX</code> et non signés <code>uX</code>, <code>X</code> étant la taille en bits (8, 16, 32, 64, 128)</li>
<li>Flottants avec <code>f32</code> et <code>f64</code></li>
<li>Caractères (<code>char</code> 4 octets, support complet d'Unicode (<code>'a'</code>, <code>'火'</code>, <code>'🔥'</code>))</li>
<li>Tuples (<code>let tup = ('a', 'b', 'c')</code>, <code>let tup = (5, 4.5)</code>)</li>
<li>Tableaux (à taille fixe; pour des tailles dynamiques, on utilise des <em>vectors</em>, comme en C++)</li>
</ul>
<p>Pas de <code>null</code> en Rust 🎊, mais une énumération standard <code>Option</code> pouvant contenir une valeur (<code>Some</code>) ou rien (<code>None</code>).</p>
<p>On définit des types personnalisés à l'aide des <code>enum</code> et <code>struct</code> :</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">enum</span><span class="token plain"> </span><span class="token type-definition class-name">IpAddressKind</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token constant" style="color:#36acaa">V4</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token constant" style="color:#36acaa">V6</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token type-definition class-name">IpAddress</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    kind</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">IpAddressKind</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    address</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>En effet, pas de <strong>classes</strong> ni de <strong>Programmation orientée Objet</strong>, mais <a href="https://doc.rust-lang.org/book/ch17-00-oop.html" target="_blank" rel="noopener noreferrer">d'autres mécanismes</a> remplacent très bien l'héritage, le polymorphisme, etc. Il n'y a d'ailleurs pas de constructeur en Rust : par convention, on définit une <em>fonction associée</em> <code>new</code> responsable de fournir une instance du type défini. C'est par exemple le cas de <code>String::new()</code>, du <a href="https://doc.rust-lang.org/std/string/struct.String.html#method.new" target="_blank" rel="noopener noreferrer">crate du même nom</a>.<br>
<!-- -->Les fonctions associées ou <em>"Associated functions"</em> sont l'équivalent des méthodes statiques en POO : des fonctions associées à un type, plutôt qu'à une instance. On les exécute avec l'opérateur <em>double colon</em> (<code>::</code>) : <code>&lt;Type&gt;::&lt;method_name&gt;</code>.</p>
<p>L'encapsulation est possible à l'aide du mot clé <code>pub</code>, qui permet de rendre publiques les modules, types, méthodes et fonctions. Par défaut, tout est privé. On peut ajouter des méthodes à un type en définissant une implémentation (<code>impl</code>) :</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token type-definition class-name">Account</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    balance</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">i64</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">impl</span><span class="token plain"> </span><span class="token class-name">Account</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">amount</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">i64</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Account</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Account</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> balance</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> amount </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">get_balance</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">i64</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">balance</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le champs <code>balance</code> est privé : il n'est pas accessible par les autres modules constituant le projet.</p>
<p>Pas d'interfaces ni d'héritage, mais Rust supporte également les <a href="https://doc.rust-lang.org/rust-by-example/generics.html" target="_blank" rel="noopener noreferrer">types génériques</a> ainsi que les <a href="https://doc.rust-lang.org/book/ch10-02-traits.html" target="_blank" rel="noopener noreferrer">Traits</a>.</p>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="ownership"><em>Ownership</em><a href="https://vinceops.me/rust-premiers-retours#ownership" class="hash-link" aria-label="Lien direct vers ownership" title="Lien direct vers ownership">​</a></h4>
<p>Cette fonctionnalité de Rust (concept unique !) qui joue un rôle majeur dans sa gestion sûre de la mémoire est basée sur 3 règles simples :</p>
<ul>
<li>Chaque valeur stockée en mémoire a une variable désignée comme son "propriétaire"</li>
<li>Il n'y a qu'un seul propriétaire à la fois</li>
<li>Quand le <em>scope</em> du propriétaire prend fin, la valeur est supprimée</li>
</ul>
<p>Lorsqu'une valeur ayant entrainé une allocation mémoire est réassignée ou passée en paramètre, on parle de "<em>move</em>" (transfert de propriété), rendant impossible l'utilisation de la variable initiale :</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Jean"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">say_hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ❌ error[E0382]: borrow of moved value: `name`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"{}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// ^ value borrowed here after move</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">say_hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Hello {}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Pour des raisons de performances, Rust ne prend pas l'initiative de faire une copie de cette valeur en mémoire et fait un <em>move</em>. Certaines valeurs sont systématiquement copiées (<em>pass by value</em>), comme les références (et non la valeur qu'elle réfère) et les types scalaires (entiers, caractères...).</p>
<p>On peut passer <code>name</code> par référence (typée <code>&amp;</code>) pour procéder à un <strong>emprunt</strong> (<em>borrow</em>) :</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Jean"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">say_hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"{}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">say_hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Hello {}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>L'emprunteur <code>say_hello</code> utilise une référence de <code>name</code>. Lorsque la fin de son scope est atteinte, rien ne se passe : le propriétaire de la valeur n'a jamais changé.<br>
<!-- -->🤔 Que se passe-t-il si l'on essaie de compiler du code modifiant la valeur pour la préfixer avec "Hello" ?</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> s </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Jean"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">prefix_with_hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">s</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"{}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> s</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">prefix_with_hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// ❌ error[E0596]: cannot borrow `*name` as mutable, as it is behind a `&amp;` reference</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token comment" style="color:#999988;font-style:italic">// ------- help: consider changing this to be a mutable</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">insert_str</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Hello "</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//  ^^^^ `name` is a `&amp;` reference, so the data it refers to cannot be borrowed as mutable</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le compilateur <strong>explique</strong> (littéralement !) que <code>name</code> ne peut pas être emprunté en tant que valeur mutable, car passé par "référence <code>&amp;</code>". Il recommande l'emploi d'une référence mutable, de type <code>&amp;mut String</code>. On applique donc 3 changements : 1- <code>name</code> doit être mutable, 2- passé en tant que "référence <code>&amp;mut</code>", 3- et <code>prefix_with_hello</code> doit accepter le bon type en paramètre :</p>
<div class="language-rust codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-rust codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> s </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Jean"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">prefix_with_hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> s</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"{}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> s</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// "Hello Jean"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">prefix_with_hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">insert_str</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Hello "</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>En résumé, l'<em>ownership</em> effectue un suivi de chaque partie de code utilisant des valeurs stockées dans le tas (<em>heap</em>), y minimise les duplications, et libère la mémoire occupée par des valeurs inutilisées.</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Je recommande au passage la lecture de <a href="https://words.steveklabnik.com/borrow-checking-escape-analysis-and-the-generational-hypothesis" target="_blank" rel="noopener noreferrer">cet excellent article</a> (teaser : on y parle aussi <strong>un peu</strong> du <em>gradual typing</em> de TypeScript).</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="conclusion">Conclusion<a href="https://vinceops.me/rust-premiers-retours#conclusion" class="hash-link" aria-label="Lien direct vers Conclusion" title="Lien direct vers Conclusion">​</a></h3>
<p>Encore un article trop long à lire et à écrire, bien qu'il ne contienne même pas 30% de ce que j'aurais voulu y rapporter tellement j'apprécie la découverte de ce langage ! Mais le but est seulement de partager mon enthousiasme avec quelques éléments techniques. Pour les plus curieux, je recommande à nouveau la consultation du <a href="https://doc.rust-lang.org/stable/book" target="_blank" rel="noopener noreferrer">Book</a> pour y découvrir, entre autres :</p>
<ul>
<li>Les <a href="https://doc.rust-lang.org/stable/book/ch04-03-slices.html#string-slices" target="_blank" rel="noopener noreferrer">slices</a></li>
<li>Le <a href="https://doc.rust-lang.org/book/ch06-02-match.html" target="_blank" rel="noopener noreferrer">pattern matching</a>, déjà suggéré <a href="https://github.com/tc39/proposal-pattern-matching" target="_blank" rel="noopener noreferrer">à la TC39</a> pour EcmaScript</li>
<li>Le <a href="https://doc.rust-lang.org/edition-guide/rust-2018/data-types/field-init-shorthand.html" target="_blank" rel="noopener noreferrer">field init shorthand</a></li>
<li>Le <a href="https://doc.rust-lang.org/book/ch11-01-writing-tests.html" target="_blank" rel="noopener noreferrer">testing</a></li>
<li>Le <a href="https://doc.rust-lang.org/stable/book/ch16-00-concurrency.html" target="_blank" rel="noopener noreferrer">threading</a></li>
<li>Etc. Lisez tout, en fait 😏.</li>
</ul>
<p>D'autres articles sur Rust (et donc WebAssembly !) viendront. Soyez prêts !</p>
<img src="https://media.giphy.com/media/jxzEhHBMmH7tm/giphy.gif" alt="Be prepared" style="width:300px;margin:20px auto;display:block">
<hr>
<p><em><a href="https://tizmah.artstation.com/" target="_blank" rel="noopener noreferrer">Credits</a> pour la superbe plage en pixel art</em> 🏖</p>]]></content:encoded>
            <category>rust</category>
            <category>vs code</category>
        </item>
        <item>
            <title><![CDATA[Git : Astuces et productivité #1]]></title>
            <link>https://vinceops.me/git-astuces-productivite-1</link>
            <guid>https://vinceops.me/git-astuces-productivite-1</guid>
            <pubDate>Wed, 01 May 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Dans ce premier article d'une série dédiée à git, j'aborde les commit atomiques.]]></description>
            <content:encoded><![CDATA[<p>Dans ce premier article d'une série dédiée à <a href="https://git-scm.com/" target="_blank" rel="noopener noreferrer"><strong>git</strong></a>, j'aborde les <strong>commit atomiques</strong>.<br>
<!-- -->Au programme de ladite série, <em>Tips &amp; tricks!</em> : raccourcis, astuces et méthodologie (<em>opinionated content!</em>).</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="commits-atomiques">Commits atomiques<a href="https://vinceops.me/git-astuces-productivite-1#commits-atomiques" class="hash-link" aria-label="Lien direct vers Commits atomiques" title="Lien direct vers Commits atomiques">​</a></h2>
<p>L'emploi des commits "atomiques" est encore peu courant, alors qu'il constitue la base de tout bon contrôle de version, en tant que concept comme en tant qu'outil, du <em>commit history</em> (avec tout ce qu'il a à offrir) à la <em>code review</em>.</p>
<p>📚 Un commit est dit <strong>atomique</strong> lorsque :</p>
<ul>
<li>Le changement qu'il apporte ne casse pas la cohérence du dépôt (compilation garantie et tests réussis).</li>
<li>Il concerne <strong>une</strong> tâche et ne peut être découpé davantage sans enfreindre la règle précédente.</li>
<li>Son message est précis et explique clairement le périmètre de son opération.</li>
</ul>
<p>✌ Et les bénéfices sont aussi nombreux qu'évidents.</p>
<p>L'atomicité tend à réduire la taille des commits et à augmenter la fréquence des <code>push</code> : le code est <strong>sauvegardé plus régulièrement</strong>.</p>
<p>Le périmètre des commits atomiques, en plus d'être clairement défini, est généralement peu fragmenté à travers la <em>codebase</em> : les <strong><em>merge conflicts</em></strong> se raréfient et <strong>l'intention</strong> des autres développeurs se devine facilement.</p>
<p><strong>L'<a href="https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History" target="_blank" rel="noopener noreferrer">historique</a> des commits</strong> devient très pertinent : chaque entrée décrit précisément une modification; couplé à une <a href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit" target="_blank" rel="noopener noreferrer">convention de <em>commit message</em></a>, il joue pratiquement le rôle de <a href="https://keepachangelog.com/fr/1.0.0/" target="_blank" rel="noopener noreferrer">changelog</a>.</p>
<p>Les <strong>revues de code sont plus efficaces</strong>, réalisables "commit par commit" : le <em>reviewer</em> peut se concentrer sur chaque modification <strong>isolée</strong>. Chacune doit aussi être <strong>complète</strong> : quand c'est approprié, documentation et tests inclus.</p>
<p>Chaque modification apportée à un fichier devient légitime : aucun hors-sujet dans les <a href="https://git-scm.com/docs/git-blame" target="_blank" rel="noopener noreferrer">git blame</a>. Terminés les commits <code>"fix bug"</code> touchant à 9 fichiers dont 150 lignes de code et 7 fonctions ! Naturellement, cela s'accompagne aussi d'une <strong>meilleure chasse des régressions</strong> (manuelle, ou avec <a href="https://git-scm.com/docs/git-bisect" target="_blank" rel="noopener noreferrer">git bisect</a> pour les <em>lords</em> 😁).</p>
<p>... etc!</p>
<img src="https://media.giphy.com/media/rlfUniMvoWZOw/giphy.gif" alt="amazed-face" style="width:200px;margin:20px auto;display:block">
<p>💡 En pratique, cela se traduit principalement par <strong>l'augmentation de la fréquence des commits</strong>.</p>
<p>Une nouvelle fonctionnalité ? <code>"feat(dashboard): add the step-by-step tutorial"</code><br>
<!-- -->Des tests manquants sur une méthode ? <code>"test(fcm): add tests for android payload factory"</code><br>
<!-- -->Toutes les indentations passées de 2 à 4 espaces (à éviter 😁) ? <code>"style: change indent. from 2 to 4 spaces"</code></p>
<p>Ces exemples de <em>commits messages</em> sont construits selon la convention suivante : <a href="https://www.conventionalcommits.org/" target="_blank" rel="noopener noreferrer">conventional commits</a>.<br>
<!-- -->Ils sont composés :</p>
<ul>
<li>d'un type (<code>feat</code>, <code>fix</code>, <code>test</code>...)</li>
<li>d'un <em>scope</em> optionnel (<code>dashboard</code>, <code>fcm</code>) faisait référence à une partie du code</li>
<li>d'un message décrivant le changement apporté</li>
</ul>
<p>Il n'y a aucun mal à faire de très petits commits, pourvu qu'ils respectent les règles citées en introduction. Il est de toute façon plus aisé de regrouper plusieurs commits en un seul, que d'en séparer un en plusieurs.<br>
<!-- -->Dernier point positif : avec un historique clair, le "<em>squash pre-merge</em>" (bouh! 🤮) n'a plus de raison d'être (mais en a-t-il déjà été autrement ? 😁).</p>]]></content:encoded>
            <category>git</category>
            <category>productivité</category>
        </item>
        <item>
            <title><![CDATA[React : Suivi des erreurs avec Bugsnag]]></title>
            <link>https://vinceops.me/react-suivi-erreurs-bugsnag</link>
            <guid>https://vinceops.me/react-suivi-erreurs-bugsnag</guid>
            <pubDate>Wed, 13 Mar 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Vendredi 18h30, après une bonne semaine de livraison continue et de revue de code, quoi de tel qu'un product manager qui entre paniqué dans le bureau en vous demandant ce que signifie ce "Uncaught ReferenceError" ?]]></description>
            <content:encoded><![CDATA[<p>Vendredi 18h30, après une bonne semaine de livraison continue et de revue de code, quoi de tel qu'un <em>product manager</em> qui entre paniqué dans le bureau en vous demandant ce que signifie ce <code>"Uncaught ReferenceError"</code> ?</p>
<p>Bien qu'il ne permette pas d'éviter cette erreur (mais <a href="https://vinceops.me/2018/04/22/typescript-partie-2-3-pourquoi-ladopter/" target="_blank" rel="noopener noreferrer">TypeScript</a> peut aider 😁), l'outil <a href="https://www.bugsnag.com/" target="_blank" rel="noopener noreferrer">Bugsnag</a> sait (entre autres) remonter automatiquement les erreurs non-gérées de votre application.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="bugsnag-breadcrumb" src="https://vinceops.me/assets/images/2019-03-13_22-50-25-4d9b3e2ff79ecb512fcb4a92943c8aea.jpg" width="766" height="452" class="img_BhpN"><br>
<em>Breadcrumbs: L'outil trace la succession d'actions ayant provoqué l'erreur</em></p></div>
<p>Les avantages sont multiples :</p>
<ul>
<li>On n'attend pas après les retours utilisateurs pour découvrir qu'une fonctionnalité provoque des <em>runtime errors</em> (#<strong>réact</strong>ivité #blagueDrôle)</li>
<li>Chaque erreur rapportée peut entraîner le déclenchement d'un Webhook (e.g. créer un issue sur Github, envoyer un message sur Slack...)</li>
<li>On peut tracer manuellement des cas critiques avec un maximum de <em>metadata</em>, facilitant la reproduction d'un bug ou usage (<em>state</em>, historique des <em>actions</em> Redux, saisies, ID, etc)</li>
</ul>
<img src="https://media.giphy.com/media/Oebj5fZNZOdwI/giphy.gif" alt="lazer-cat" style="width:250px;margin:20px auto;display:block">
<blockquote>
<p>Disclaimer :</p>
<ul>
<li><a href="https://sentry.io/" target="_blank" rel="noopener noreferrer">Sentry</a> est une excellente alternative à Bugsnag</li>
<li>Les exemples donnés ci-après nécessitent <strong>React 16+</strong> et ses <a href="https://reactjs.org/docs/error-boundaries.html" target="_blank" rel="noopener noreferrer">Error Boundaries</a> pour fonctionner.</li>
</ul>
</blockquote>
<p>Après avoir créé un nouveau projet sur Bugsnag (Browser &gt; React), on obtient une clé API permettant d'émettre de nouveaux "événements" (erreur gérée, erreur non-gérée, rapport personnalisé, etc).</p>
<img src="https://vinceops.me/2019-03-07_00-19-59.jpg" alt="nouveau-projet-bugsnag" width="550">
<p>Il ne reste qu'à intégrer le client au projet !</p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">yarn add @bugsnag/js @bugsnag/plugin-react</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># ou npm install @bugsnag/js @bugsnag/plugin-react</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Les paquets sont fournis avec leurs définitions 😌 #typeSafety</p></div></div>
<p>On crée un client bugsnag :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// src/&lt;whatever/bugsnag-client.ts</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> bugsnag </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@bugsnag/js'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> bugsnagClient </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">bugsnag</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  apiKey</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">BUGSNAG_API_KEY</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">beforeSend</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">report</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// les rapports sont ignorés si l'app n'est pas en production</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">NODE_ENV</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'production'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      report</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ignore</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// le state est ajouté aux données meta du rapport (debugging facilité)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    report</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">metadata</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> store</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> bugsnagClient</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Deux options sont utilisées :</p>
<ul>
<li><code>apiKey</code>, la clé API fournie par Bugsnag</li>
<li><code>beforeSend</code>, un <em>callback</em> appelé avant chaque émission</li>
</ul>
<p>On peut ajouter toute sorte de <a href="https://docs.bugsnag.com/platforms/javascript/react/customizing-error-reports/" target="_blank" rel="noopener noreferrer">données</a> au rapport remonté, facilitant le travail de debug/analyse.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="les-erreurs-non-gérées--error-boundary">Les erreurs non-gérées : Error Boundary<a href="https://vinceops.me/react-suivi-erreurs-bugsnag#les-erreurs-non-g%C3%A9r%C3%A9es--error-boundary" class="hash-link" aria-label="Lien direct vers Les erreurs non-gérées : Error Boundary" title="Lien direct vers Les erreurs non-gérées : Error Boundary">​</a></h2>
<p>Pour rapporter automatiquement les erreurs non gérées, on crée un <em>component</em> Error Boundary <a href="https://docs.bugsnag.com/platforms/javascript/react/" target="_blank" rel="noopener noreferrer">avec le client</a> :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// src/&lt;whatever&gt;/BugsnagBoundary.ts</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> ReactNode </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">  </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> bugsnagReact </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@bugsnag/plugin-react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> bugsnagClient </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./bugsnag-client.ts'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">bugsnagClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">use</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">bugsnagReact</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> BugsnagBoundary</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> FunctionComponent</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> FallbackComponent</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ReactNode </span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> bugsnagClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getPlugin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> BugsnagBoundary</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><code>BugsnagBoundary</code> est directement utilisable pour envelopper notre <em>component</em> de plus haut niveau :</p>
<div class="language-jsx codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-jsx codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">BugsnagBoundary</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">App</span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">BugsnagBoundary</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img src="https://media.giphy.com/media/nYSlA9xdfKuNa/giphy.gif" alt="safety-net" style="width:400px;margin:20px auto;display:block">
<p>Cependant, cette solution présente deux défauts :</p>
<ul>
<li>Aucun contenu n'est affiché à l'utilisateur si c'est l'étape de rendu (<em>rendering</em>) qui provoque une erreur. Bien que ladite erreur soit remontée à Bugsnag. Un <em>component</em> de remplacement peut être affiché, cas échéant, en le passant à la prop <code>FallbackComponent</code>.</li>
<li>Les erreurs provoquées lors des phases de conception ne sont plus remontées visuellement par les outils de développement (<code>react-error-overlay</code>, <code>react-hot-loader</code>, etc).</li>
</ul>
<p>On peut wrapper <code>BugsnagBoundary</code> dans un nouveau composant pour y remédier :</p>
<div class="language-jsx codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-jsx codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// src/&lt;whatever&gt;/ErrorBoundary.ts</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">React</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">FunctionComponent</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">BugsnagBoundary</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">FunctionComponent</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token maybe-class-name">FallbackComponent</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">ReactNode</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> bugsnagClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getPlugin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">ErrorBoundary</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function-variable function maybe-class-name" style="color:#d73a49">FunctionComponent</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter punctuation" style="color:#393A34">{</span><span class="token parameter"> children </span><span class="token parameter punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">NODE_ENV</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'production'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">BugsnagBoundary</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">FallbackComponent</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript maybe-class-name" style="color:#00009f">FallbackComponent</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">children</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">BugsnagBoundary</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> children</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">default</span><span class="token plain"> </span><span class="token maybe-class-name">ErrorBoundary</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><code>BugsnagBoundary</code> n'est rendu qu'en production et affiche <code>FallbackComponent</code> si <code>children</code> ne peut pas l'être. Autrement, seul <code>children</code> est rendu et l'arbre des <em>components</em> reste inchangé.</p>
<p><code>FallbackComponent</code> reçoit les props suivantes :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">FallbackComponentProps</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  error</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Error</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  info</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> componentStack</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>On wrap ensuite notre <code>&lt;App/&gt;</code> avec <code>ErrorBoundary</code>.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="les-erreurs-gérées--notify">Les erreurs gérées : <code>notify</code><a href="https://vinceops.me/react-suivi-erreurs-bugsnag#les-erreurs-g%C3%A9r%C3%A9es--notify" class="hash-link" aria-label="Lien direct vers les-erreurs-gérées--notify" title="Lien direct vers les-erreurs-gérées--notify">​</a></h2>
<p>Les erreurs gérées (et les rapports personnalisés) peuvent être émis avec <a href="https://docs.bugsnag.com/platforms/javascript/react/reporting-handled-errors/" target="_blank" rel="noopener noreferrer"><strong><code>notify</code></strong></a> :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// dans un processus critique (en cas d'erreur), ou dans un flux sensible :</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">bugsnagClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">notify</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Unexpected error during Sign Up'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  metaData</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> validation</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> errors</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> signUpForm </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  severity</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'info'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Ici aussi, on ajoute un maximum d'informations facilitant la compréhension du contexte (en prenant garde de ne jamais aller à l'encontre de la RGPD 😬).</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="suivi-">Suivi 🧐<a href="https://vinceops.me/react-suivi-erreurs-bugsnag#suivi-" class="hash-link" aria-label="Lien direct vers Suivi 🧐" title="Lien direct vers Suivi 🧐">​</a></h2>
<p>Depuis l'inbox (dans le dashboard), on peut suivre en temps quasi-réel les rapports, leur fréquence, la date de dernière occurrence, les assigner à un développeur, les marquer comme <em>Fixed</em>, etc.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="bugsnag-react" src="https://vinceops.me/assets/images/bugsnag_report-791633af80ee63d7b3a63a740d6cc293.jpg" width="1525" height="281" class="img_BhpN"></p></div>
<p>Dans le détail de chaque rapport, on trouve, en plus des <em>Breadcrumbs</em> : la <em>stacktrace</em>, un extrait du code ayant provoqué l'erreur (ou émis le rapport), les données meta rapportées, des données sur l'appareil de l'utilisateur, etc.</p>
<blockquote>
<p>📜 Les <em>source maps</em> doivent être hébergées sur <a href="https://docs.bugsnag.com/platforms/javascript/source-maps/" target="_blank" rel="noopener noreferrer">Bugsnag</a>, pour permettre le bon usage de cette fonctionnalité (sinon, c'est la portion de code <em>minifiée</em>/transpilée qui est affichée).</p>
</blockquote>
<img src="https://media.giphy.com/media/k39w535jFPYrK/giphy.gif" alt="enjoy-coding" style="width:400px;margin:20px auto;display:block">
<p><em>Enjoy coding!</em></p>
<p>Merci à mon très inspirant collègue (et super lead frontend dev 💓) <a href="https://twitter.com/timurrustamov8" target="_blank" rel="noopener noreferrer">@Timur</a>, pour son indéfectible soutien 🔥.</p>]]></content:encoded>
            <category>react</category>
            <category>productivité</category>
        </item>
        <item>
            <title><![CDATA[TypeScript : Typage et Généricité]]></title>
            <link>https://vinceops.me/typescript-typage-genericite</link>
            <guid>https://vinceops.me/typescript-typage-genericite</guid>
            <pubDate>Sun, 10 Feb 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[La généricité permet d'écrire des définitions (de classes, interfaces, fonctions, types...) paramétriques. On appelle ces définitions des Génériques. Présents sous le même nom dans Java (1.5), C# (2), ils existent dans TypeScript depuis sa création (merci qui ? Merci Anders !).]]></description>
            <content:encoded><![CDATA[<p>La <a href="https://en.wikipedia.org/wiki/Generic_programming" target="_blank" rel="noopener noreferrer">généricité</a> permet d'écrire des définitions (de classes, interfaces, fonctions, types...) paramétriques. On appelle ces définitions des <a href="https://www.typescriptlang.org/docs/handbook/generics.html" target="_blank" rel="noopener noreferrer">Génériques</a>. Présents sous le même nom dans Java (1.5), C# (2), ils existent dans TypeScript depuis sa création (merci qui ? Merci Anders !).</p>
<p>Un exemple très commun en TypeScript est celui des tableaux, avec <code>Array&lt;T&gt;</code>. <code>T</code> est appelé "paramètres de type" (<em>type parameter</em>, à ne pas confondre avec un type de paramètre 🙃).</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> items</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">Array</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">number</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// ok</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'a'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// erreur: argument of type 'a' is not assignable to parameter of type 'number'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// "n" est déduit comme étant de type 'number'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> results </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> items</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> n</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">toFixed</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// ["1.0", "2.0", "3.0", "4.0"]</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Les mêmes méthodes (<code>push</code>, <code>map</code>, etc) et la même analyse statique existent avec <code>Array&lt;string&gt;</code>, <code>Array&lt;Date&gt;</code>, etc. <code>Array</code> est dit "type générique".</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>C'est aussi vrai pour <code>Map&lt;K, V&gt;</code>, <code>Set&lt;T&gt;</code>, <code>Promise&lt;T&gt;</code>, <a href="https://github.com/ReactiveX/rxjs/blob/master/src/internal/Observable.ts" target="_blank" rel="noopener noreferrer"><code>Observable&lt;T&gt;</code></a> (RxJS), etc.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="show-time-">Show time 🎉<a href="https://vinceops.me/typescript-typage-genericite#show-time-" class="hash-link" aria-label="Lien direct vers Show time 🎉" title="Lien direct vers Show time 🎉">​</a></h3>
<p><em>Certains exemples sont volontairement simplistes, l'objectif étant de lever toute ambiguïté en se concentrant sur les sujets de la généricité et du typage 🤗</em></p>
<p>Grâce aux generics, il est possible de :</p>
<p>🌟 <strong>Déclarer des contraintes génériques</strong></p>
<p>On définit une <strong>fonction générique</strong> <code>pick</code> <em>type-safe</em> permettant de récupérer un extrait d'objet, ici, à l'aide de <code>K extends keyof T</code>, dit "<code>K</code> <strong>contraint</strong> par <code>T</code>".</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">pick</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name constant" style="color:#36acaa">T</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">,</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name constant" style="color:#36acaa">K</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name keyword" style="color:#00009f">extends</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name keyword" style="color:#00009f">keyof</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name constant" style="color:#36acaa">T</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">source</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">keys</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">K</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Partial</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> result</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Partial</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  keys</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> source</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> user </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> weight</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">55</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Winry'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> birthDate</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Date</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'1985-06-13'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">pick</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">user</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'name'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'weight'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// { name: 'Winry', weight: 55 }</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Bien sûr, tout est analysé/déduit par le compilateur <code>tsc</code> et l'IDE sait aussi faire l'auto-complétion des propriétés saisies (<code>name</code> et <code>weight</code>) 🔥.</p>
<p>🌟 <strong>Obtenir les propriétés d'un certain type d'une classe ou interface</strong></p>
<p>En utilisant les types conditionnels (<em>conditional types</em>), qui prennent la forme d'une expression ternaire utilisant <code>extends</code> :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">StringProperty</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">string</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">never</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">User</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  birthDate</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Date</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  isAdmin</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  firstName</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  lastName</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name constant" style="color:#36acaa">S1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> StringProperty</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">User</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 'firstName' | 'lastName'</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>On peut rendre ce type générique ... encore plus générique !</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// toutes les propriétés de type "A" du type "T"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">PropertyOfType</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> </span><span class="token class-name constant" style="color:#36acaa">A</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name constant" style="color:#36acaa">A</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">never</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// décliné en :</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">StringProperty</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> PropertyOfType</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">NumberProperty</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> PropertyOfType</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">MethodProperty</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> PropertyOfType</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">args</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>&nbsp;<br>
<!-- -->🌟 <strong>Définir des types élaborés (<em>mapped types</em>)</strong></p>
<p>Rendus possibles grâce à la généricité, vous connaissez la plupart d'entre eux si vous utilisez TypeScript régulièrement :</p>
<ul>
<li><code>Partial&lt;T&gt;</code> : Type ayant toutes les propriétés de <code>T</code>, optionnelles (modificateur <code>?</code>).</li>
<li><code>Required&lt;T&gt;</code> : Type ayant toutes les propriétés de <code>T</code>, requises (modificateur <code>-?</code>).</li>
<li><code>Readonly&lt;T&gt;</code> : Type ayant toutes les propriétés de <code>T</code>, non ré-assignables (modificateur <code>readonly</code>).</li>
<li><code>Pick&lt;T, K extends keyof T&gt;</code> : Type ayant toutes les propriétés <code>K</code> de <code>T</code>.</li>
</ul>
<p>Quelques autres qui, bien qu'absents des <code>lib.*.d.ts</code>, sont très communément utilisés dans les projets TypeScript:</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Type ayant toutes les propriétés de T, pouvant aussi être `null` </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Nullable</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Type ayant toutes les propriétés de T, sans modificateur `readonly`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Writable</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Type ayant toutes les propriétés de T sauf celles données pour K</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// e.g.: Omit&lt;User, 'firstName' | 'lastName'&gt; </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Omit</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> </span><span class="token class-name constant" style="color:#36acaa">K</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">extends</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">keyof</span><span class="token class-name"> </span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Pick</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Exclude</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">K</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// `Partial&lt;T&gt;` supportant plusieurs niveaux de profondeur (sous-objets, sous-sous-objets, etc)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">DeepPartial</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">Array</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name keyword" style="color:#00009f">infer</span><span class="token class-name"> </span><span class="token class-name constant" style="color:#36acaa">U</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token builtin">Array</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">DeepPartial</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">U</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> DeepPartial</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>L'implémentation de <code>DeepPartial</code> ci-dessus est incomplète (pour des raisons de lisibilité) : elle doit aussi intégrer l'assignation des types <code>Date</code> (à conserver "tel quel") et <code>ReadonlyArray&lt;T&gt;</code>.</p></div></div>
<img src="https://media.giphy.com/media/3oKIPnAiaMCws8nOsE/giphy.gif" alt="cute-cat" style="width:300px;margin:20px auto;display:block">
<p>🌟 <strong>Introduire des variables de Type à déduire (<code>infer</code>)</strong></p>
<p>L'introduction des types conditionnels (TypeScript 2.8), avec le mot-clé <code>extends</code>, a aussi introduit le mot-clé <code>infer</code>, qui permet de déclarer une variable de type déduit.<br>
<code>DeepPartial&lt;T&gt;</code> en montre un premier exemple ci-dessus, en transformant les <code>Array&lt;U&gt;</code> en <code>Array&lt;DeepPartial&lt;U&gt;&gt;</code> (souhaité) et non en <code>DeepPartial&lt;Array&lt;U&gt;&gt;</code> (insensé).</p>
<p>Autres exemples :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Type de retour d'une fonction T, introduit comme "R"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ReturnType</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">args</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">infer</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">R</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">R</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Type déduit "U" d'une Promise, d'un Array, d'une fonction, ou T</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Unpacked</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">infer</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">U</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">U</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">args</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">infer</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">U</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">U</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">Promise</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name keyword" style="color:#00009f">infer</span><span class="token class-name"> </span><span class="token class-name constant" style="color:#36acaa">U</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">U</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name constant" style="color:#36acaa">U1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Unpacked</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// number</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name constant" style="color:#36acaa">U2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Unpacked</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name constant" style="color:#36acaa">U3</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Unpacked</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Unpacked</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">&gt;&gt;&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name constant" style="color:#36acaa">U4</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Unpacked</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Date</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Date</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Type (tuple) contenant les types des paramètres d'une fonction</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Parameters</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">extends</span><span class="token class-name"> </span><span class="token class-name punctuation" style="color:#393A34">(</span><span class="token class-name operator" style="color:#393A34">...</span><span class="token class-name">args</span><span class="token class-name operator" style="color:#393A34">:</span><span class="token class-name"> </span><span class="token class-name builtin">any</span><span class="token class-name punctuation" style="color:#393A34">[</span><span class="token class-name punctuation" style="color:#393A34">]</span><span class="token class-name punctuation" style="color:#393A34">)</span><span class="token class-name"> </span><span class="token class-name operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">args</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">infer</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">P</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">never</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// type T1 = Parameters&lt;typeof Math.min&gt; // [number[]]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Type (tuple) contenant les types des paramètres d'un constructeur</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ConstructorParameters</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">extends</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">new</span><span class="token class-name"> </span><span class="token class-name punctuation" style="color:#393A34">(</span><span class="token class-name operator" style="color:#393A34">...</span><span class="token class-name">args</span><span class="token class-name operator" style="color:#393A34">:</span><span class="token class-name"> </span><span class="token class-name builtin">any</span><span class="token class-name punctuation" style="color:#393A34">[</span><span class="token class-name punctuation" style="color:#393A34">]</span><span class="token class-name punctuation" style="color:#393A34">)</span><span class="token class-name"> </span><span class="token class-name operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">args</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">infer</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">P</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">never</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// type T2 = ConstructorParameters&lt;typeof Account&gt;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>&nbsp;<br>
<!-- -->🌟 <strong>Utiliser un "paramètre du reste" générique</strong></p>
<p>Dans cet exemple, avec <code>...T[]</code>.<br>
<!-- -->On définit un type <code>ColorFilter</code> attendant soit : une et une seule valeur de type <code>Color</code>, <strong>ou</strong> un opérateur <code>'AND'</code> ou <code>'OR'</code> suivi d'<strong>au moins</strong> deux valeurs de type <code>Color</code>.</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">FilterAndOr</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> </span><span class="token class-name constant" style="color:#36acaa">K</span><span class="token class-name"> </span><span class="token class-name operator" style="color:#393A34">=</span><span class="token class-name"> </span><span class="token class-name string" style="color:#e3116c">'AND'</span><span class="token class-name"> </span><span class="token class-name operator" style="color:#393A34">|</span><span class="token class-name"> </span><span class="token class-name string" style="color:#e3116c">'OR'</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">K</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">...</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Color</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'red'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'green'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'blue'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'yellow'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'white'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Permet l'utilisation des valeurs:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ["blue"]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ["AND", "blue", "red"]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ["OR", "yellow", "green", "red"]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ["AND", "blue", "white", "red", "green"]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ColorFilter</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> FilterAndOr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Color</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>&nbsp;<br>
<!-- -->🌟 <strong>Etc, etc, etc</strong></p>
<p>Il existe une infinité de cas d'usage des Generics et il m'est impossible d'en faire une liste exhaustive, cependant, comme tout bon outil, attention à ne pas tomber dans le piège habituel : quand on a un marteau, tout ressemble à un clou 😁.</p>
<img src="https://media.giphy.com/media/l2JhucuqxI0UswQa4/giphy.gif" alt="weak-tools" style="width:300px;margin:20px auto;display:block">
<p>Pour toujours plus de TypeScript 💕, je vous invite à regarder <a href="https://www.youtube.com/watch?v=ET4kT88JRXs" target="_blank" rel="noopener noreferrer">cette vidéo</a> d'Anders Hejlsberg à la DotJS 2018 à Paris. <em>Enjoy!</em></p>]]></content:encoded>
            <category>typescript</category>
        </item>
        <item>
            <title><![CDATA[Nest : Tests E2E et Effets de bord]]></title>
            <link>https://vinceops.me/nest-e2e-tests-effets-de-bord</link>
            <guid>https://vinceops.me/nest-e2e-tests-effets-de-bord</guid>
            <pubDate>Wed, 12 Dec 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Dans le monde merveilleux des tests d'intégration et E2E (end-to-end, de "bout en bout" 🥐), il est fréquent de vérifier le bon fonctionnement d'un service tiers. Cependant, dans un scénario complet, les interactions avec ledit service sont parfois faites de manière asynchrone car non-critiques ou non-bloquantes. Alors comment les tester ?]]></description>
            <content:encoded><![CDATA[<p>Dans le monde merveilleux des tests d'intégration et E2E (<em>end-to-end</em>, de "bout en bout" 🥐), il est fréquent de vérifier le bon fonctionnement d'un service tiers. Cependant, dans un scénario complet, les interactions avec ledit service sont parfois faites de manière asynchrone car non-critiques ou non-bloquantes. Alors comment les tester ?</p>
<img src="https://media.giphy.com/media/Nm8ZPAGOwZUQM/giphy.gif" alt="question-cat" style="width:300px;margin:20px auto;display:block">
<p>Notre application (API REST) est développée avec <a href="https://nestjs.com/" target="_blank" rel="noopener noreferrer">Nest</a>; <a href="https://jestjs.io/" target="_blank" rel="noopener noreferrer">Jest</a> sert de framework et lanceur de tests (unitaires, d'intégration, E2E), <a href="https://www.npmjs.com/package/supertest" target="_blank" rel="noopener noreferrer">supertest</a> est utilisé pour exécuter des assertions HTTP.</p>
<p>Suite à un appel HTTP, on souhaite vérifier la mise à jour d'un document dans une base de données Elasticsearch, sachant que l'exécution de celle-ci est asynchrone : c'est un effet de bord. Le client reçoit une réponse <strong>avant</strong> que la mise à jour ne soit effective.</p>
<blockquote>
<p>🕺 Les exemples de code ci-après sont volontairement restreints à une forme simple et concise, facilitant leur lecture et leur compréhension</p>
</blockquote>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="test-first">Test first<a href="https://vinceops.me/nest-e2e-tests-effets-de-bord#test-first" class="hash-link" aria-label="Lien direct vers Test first" title="Lien direct vers Test first">​</a></h3>
<p>Une première approche naïve (et invalide 🤷) consiste à faire une assertion immédiate, considérant qu'Elasticsearch a déjà été mis à jour :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">it</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'should update the value in Elasticsearch'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// appel HTTP</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">request</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">server</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">put</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">endpointURL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// PUT @ "/users/:userId"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">send</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">input</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// { firstName: 'Mike' }</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">expect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">HttpStatus</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">NO_CONTENT</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// récupération de la donnée &amp; assertion</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> document </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> elasticsearchService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">UserIndex</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> userId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">expect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">firstName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">toBe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">updatedUser</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">firstName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>La majorité des exécutions de ce test se soldera par un échec puisque la réponse HTTP arrivera <strong>avant</strong> qu'Elastic n'ait reçu l'ordre de (ou n'ait pu) se mettre à jour. Cependant, l'essentiel y est. Il ne reste qu'à attendre le succès de notre assertion en la ré-exécutant jusqu'à ce qu'elle passe, ou que le test expire (<em>timeout</em>).</p>
<p>Si le scénario n'est toujours pas clair, voici une ébauche du contrôleur gérant cette route de mise à jour :</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="contrôleur">Contrôleur<a href="https://vinceops.me/nest-e2e-tests-effets-de-bord#contr%C3%B4leur" class="hash-link" aria-label="Lien direct vers Contrôleur" title="Lien direct vers Contrôleur">​</a></h3>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Put</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/users/:userId'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">updateUser</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Param</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'userId'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> userId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Body</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ValidationPipe</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> user</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> UserInputDto</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">usersService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">update</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">userId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> user</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">elasticsearchService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">update</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">UserIndex</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> userId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">user </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Contrairement à l'exécution de <code>usersService.update</code>, le contrôleur n'attend pas celle de <code>elasticsearchService.update</code> : il envoie immédiatement une réponse.</p>
<blockquote>
<p>⚠ Dans une application réelle, le déclenchement de la synchronisation d'Elasticsearch devrait être effectuée dans/par <code>usersService</code>, avec (par exemple) un gestionnaire d'événements. Pas dans le code du contrôleur 😏.</p>
</blockquote>
<hr>
<p>On souhaite donc écrire un flux consistant à :</p>
<ol>
<li>À intervalle fixe,</li>
</ol>
<ul>
<li>(Ré-)Exécuter l'assertion,</li>
<li>Ignorer l'erreur lancée s'il y en a une (échec de l'assertion), sauf runtime errors relevant d'un problème de code (<code>TypeError</code>, <code>ReferenceError</code>)</li>
<li>"Compléter" si une valeur est émise 🎉, <strong>ou</strong> <em>timeout</em> si le temps imparti est écoulé 😿</li>
</ul>
<blockquote>
<p>⏲ Dans Jest, le délai d'expiration d'un test est de 5 secondes par défaut. Il est possible de le modifier en utilisant <a href="https://jestjs.io/docs/en/jest-object.html#jestsettimeouttimeout" target="_blank" rel="noopener noreferrer">jest.setTimeout</a>.</p>
</blockquote>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="implémentation">Implémentation<a href="https://vinceops.me/nest-e2e-tests-effets-de-bord#impl%C3%A9mentation" class="hash-link" aria-label="Lien direct vers Implémentation" title="Lien direct vers Implémentation">​</a></h3>
<p>Le test est modifié pour confier l'exécution de l'assertion à une fonction <code>waitForAssertion</code>, responsable dudit flux :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">it</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'should asynchronously update the value in Elasticsearch'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">request</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">server</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">put</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">endpointURL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">send</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">input</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">expect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">HttpStatus</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">NO_CONTENT</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">waitForAssertion</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> document </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> elasticsearchService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">UserIndex</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> userId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">expect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">firstName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">toBe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">updatedUser</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">firstName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Et le code de <code>waitForAssertion</code>, écrit avec <a href="https://rxjs-dev.firebaseapp.com/" target="_blank" rel="noopener noreferrer">RxJS</a> (qui fait partie des dépendances de Nest) :
<em>Il existe bien sûr d'autres moyens d'atteindre le même objectif, avec ou sans RxJs.</em></p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> from</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> interval</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> throwError </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'rxjs'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> catchError</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> first</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> switchMap</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> timeout </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'rxjs/operators'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * (Doc. et tests disponibles dans le Gist en fin d'article 📚)</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">waitForAssertion</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">assertion</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  timeoutDelay</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  intervalDelay</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 1. À intervalle fixe,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">interval</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">intervalDelay</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pipe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 2. (Ré-)Exécuter l'assertion,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">switchMap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">Promise</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">assertion</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 3. Ignorer l'erreur lancée s'il y en a une (échec de l'assertion), sauf runtime errors relevant d'un problème de code</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">catchError</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err </span><span class="token keyword" style="color:#00009f">instanceof</span><span class="token plain"> </span><span class="token class-name">ReferenceError</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> err </span><span class="token keyword" style="color:#00009f">instanceof</span><span class="token plain"> </span><span class="token class-name">TypeError</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">throwError</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 4.1. "Compléter" si une valeur est émise 🎉,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">first</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 4.2. ou timeout si le temps imparti est écoulé 😿</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">timeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">timeoutDelay</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">toPromise</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img src="https://media.giphy.com/media/EmMWgjxt6HqXC/giphy.gif" alt="cat-stream" style="width:400px;margin:20px auto;display:block">
<p>Code <strong>documenté et testé</strong> de <code>waitForAssertion</code> : <a href="https://gist.github.com/VinceOPS/56e25ed3f22822202ec92abeb80eaa80" target="_blank" rel="noopener noreferrer">Gist</a>.</p>]]></content:encoded>
            <category>nest</category>
            <category>node.js</category>
            <category>testing</category>
        </item>
        <item>
            <title><![CDATA[TypeScript : résolution des modules JSON]]></title>
            <link>https://vinceops.me/2018/12/03/typescript-json-modules-resolution</link>
            <guid>https://vinceops.me/2018/12/03/typescript-json-modules-resolution</guid>
            <pubDate>Mon, 03 Dec 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Cette fonctionnalité de TypeScript disponible depuis la version 2.9 du langage permet d'améliorer la sûreté du typage (type safety) dans quelques cas d'utilisations qui, bien qu'assez spécifiques, peuvent s'avérer critiques pour une application.]]></description>
            <content:encoded><![CDATA[<p>Cette fonctionnalité de <a href="https://vinceops.me/2018/04/22/typescript-partie-1-3-presentation/" target="_blank" rel="noopener noreferrer">TypeScript</a> disponible depuis la <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html" target="_blank" rel="noopener noreferrer">version 2.9</a> du langage permet d'améliorer la sûreté du typage (<em>type safety</em>) dans quelques cas d'utilisations qui, bien qu'assez spécifiques, peuvent s'avérer critiques pour une application.</p>
<p>L'article n'a pas pour vocation de faire l'inventaire desdits cas mais de présenter le concept avec des exemples pratiques, transposables à tout type d'applications.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="configuration">Configuration<a href="https://vinceops.me/2018/12/03/typescript-json-modules-resolution#configuration" class="hash-link" aria-label="Lien direct vers Configuration" title="Lien direct vers Configuration">​</a></h2>
<p>La <a href="https://www.typescriptlang.org/docs/handbook/module-resolution.html" target="_blank" rel="noopener noreferrer">résolution des modules</a> <strong>JSON</strong> est activée par l'option de compilation <code>resolveJsonModule</code> et permet aux développeurs d'écrire du code exploitant la structure (déduite) du JSON importé.</p>
<p>Les exemples ci-après utilisent un fichier <code>tsconfig.json</code> contenant notamment les valeurs suivantes :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token string-property property" style="color:#36acaa">"compilerOptions"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"module"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"commonjs"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"esModuleInterop"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"resolveJsonModule"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 💟</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"strict"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain">"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="cas-pratiques">Cas pratiques<a href="https://vinceops.me/2018/12/03/typescript-json-modules-resolution#cas-pratiques" class="hash-link" aria-label="Lien direct vers Cas pratiques" title="Lien direct vers Cas pratiques">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="fichier-de-configuration">Fichier de configuration<a href="https://vinceops.me/2018/12/03/typescript-json-modules-resolution#fichier-de-configuration" class="hash-link" aria-label="Lien direct vers Fichier de configuration" title="Lien direct vers Fichier de configuration">​</a></h3>
<p>Il est commun d'utiliser un fichier de configuration dans les scripts et applications JS/TS. Dans l'exemple suivant (totalement fictif et scabreux, mais tout aussi démonstratif), un script est responsable de vérifier le bon fonctionnement (<em>health check</em>) de services d'envoi de SMS.</p>
<blockquote>
<p>sms-settings.json</p>
</blockquote>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"providers"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">"twilio"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string-property property" style="color:#36acaa">"apiKey"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1b3b5543-e4c5"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string-property property" style="color:#36acaa">"expectedMessage"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Hello from Twilio"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string-property property" style="color:#36acaa">"expectedStatus"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">"messagebird"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string-property property" style="color:#36acaa">"apiKey"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"b78ab91a-4fe5"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string-property property" style="color:#36acaa">"expectedMessage"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Hi from Messagebird"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string-property property" style="color:#36acaa">"expectedStatus"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"200"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<blockquote>
<p>Notez la valeur <code>"200"</code> typée comme une chaîne de caractères dans <code>messagebird.expectedStatus</code> (⚠ Spoiler alert : on veut provoquer une erreur de compilation 😁).</p>
</blockquote>
<p>Ces configurations sont importées et utilisées par le script suivant :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/* script.ts */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> settings </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./sms-settings.json'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// [...]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> providers </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> settings</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">providers</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> provider </span><span class="token keyword" style="color:#00009f">of</span><span class="token plain"> Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">entries</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">providers</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">checkSmsProviderStatus</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">provider</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> provider</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/* sms-check.ts */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">ISmsProviderConfiguration</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  apiKey</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  expectedMessage</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  expectedStatus</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">checkSmsProviderStatus</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  providerName</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  config</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ISmsProviderConfiguration</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// [...]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le type de <code>providers</code> (Ligne 5) est ainsi déduit et conforme au contenu de <code>sms-settings.json</code> 😍 :</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="resolveJsonModule-typeof-providers" src="https://vinceops.me/assets/images/2018-12-02_14-16-15-694d83422cb542f773f6d5d68d1fbc49.jpg" width="416" height="288" class="img_BhpN"></p></div>
<p>Le type de <code>provider[1]</code> (Ligne 8) peut être rapproché à :</p>
<div class="language-js codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-js codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">apiKey</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">expectedMessage</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 200 et "200" entraînent une déduction de : "string" ou "number"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">expectedStatus</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> string </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>et n'est donc <strong>pas</strong> compatible avec le type <code>ISmsProviderConfiguration</code> spécifié par <code>checkSmsProviderStatus</code> (à cause du type de <code>expectedStatus</code>) :</p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">$ tsc</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">script.ts:8:39 - error TS2345: Argument of type [...] is not assignable  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">to parameter of type 'ISmsProviderConfiguration'.  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[...]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Types of property 'expectedStatus' are incompatible.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      Type 'string' is not assignable to type 'number'.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">8   checkSmsProviderStatus(provider[0], provider[1]);  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                        ~~~~~~~~~~~</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>En remplaçant <code>"200"</code> par <code>200</code> (<code>expectedStatus</code>), le code compile sans erreur ✅<br>
<!-- -->C'est donc le compilateur qui garantie le bon typage des données de configuration : <strong>how cool is it?</strong></p>
<img src="https://media.giphy.com/media/xTiQyBOIQe5cgiyUPS/giphy.gif" alt="not-bad" style="width:400px;margin:20px auto;display:block">
<p>Ce n'est pas tout ! Du point de vue de la <em>developer experience</em>, il existe un cas d'utilisation encore plus commun où cette fonctionnalité est très puissante : l'internationalisation d'une application.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="traductions">Traductions<a href="https://vinceops.me/2018/12/03/typescript-json-modules-resolution#traductions" class="hash-link" aria-label="Lien direct vers Traductions" title="Lien direct vers Traductions">​</a></h3>
<p>L'utilisation de tableaux associatifs, comme des fichiers de traductions (clé-valeur), accompagné de son exemple capilo-tracté au typage excessif totalement assumé ➡</p>
<div class="language-js codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-js codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// fr.json</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"Il n'a pas dit bonjour"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Il n'a pas dit bonjour"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"Du coup, son code n'était pas clair"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Du coup, son code n'était pas clair"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// en.json</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"Il n'a pas dit bonjour"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"He did not say hello"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"Du coup, son code n'était pas clair"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"So, his code was not clear"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"Oh, vraiment ?"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"O RLY?"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Avec le code exploitant ces fichiers de traductions, découpée en plusieurs étapes :</p>
<p><strong>1</strong> - Les imports et le typage des clés de traductions.</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> frLocales </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./fr.json'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> enLocales </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./en.json'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// union de toutes les propriétés communes à fr.json et en.json</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">TranslationKeys</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> frLocales </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> enLocales</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="resolveJsonModule-i18n-keys" src="https://vinceops.me/assets/images/2018-12-02_22-42-15-f1d40c661f7875fc724b58a7e80b0ba0.jpg" width="595" height="100" class="img_BhpN"></p></div>
<p><strong>2</strong> - La déclaration des langues et l'association des traductions correspondantes.</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Language</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'en'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'fr'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DEFAULT_LANG</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Language </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'fr'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// composition des langues possibles et de leurs traductions</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">TranslationsMap</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">l </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> Language</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// module JSON: ensemble de couples clé-traduction</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">k </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> TranslationKeys</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> translations</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> TranslationsMap </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fr</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> frLocales</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  en</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> enLocales</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><strong>3</strong> - Et l'exploitation de ces initialisations.</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">translate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> TranslationKeys</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> locale</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Language </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DEFAULT_LANG</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> translations</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">locale</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">translate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Il n'a pas dit bonjour"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">translate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Du coup, son code n'était pas clair"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'en'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ===&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Il n'a pas dit bonjour</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// So, his code was not clear</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="resolveJsonModule-autocomplete-i18n" src="https://vinceops.me/assets/images/2018-12-02_22-34-37-5e2cc443b111131c4d95d2a68fdeae86.jpg" width="618" height="74" class="img_BhpN"></p></div>
<p>&nbsp;</p>
<p>Ce code présente quelques inconvénients :</p>
<ul>
<li>Les nouvelles langues ont besoin d'être importées et intégrées manuellement</li>
<li>Il va (quelque peu 🙄) corser le <em>code splitting</em> et l'optimisation du <em>lazy loading</em> d'une application frontend</li>
</ul>
<p>Cependant, il a aussi quelques avantages :</p>
<ul>
<li>Autocomplétion des clés de traduction et des langues disponibles</li>
<li><em>Type safety</em> des clés (et langues) utilisées (une clé supprimée ou modifiée par inadvertance empêchera la compilation du code)</li>
<li>Garantie que chaque clé utilisée existe dans chaque fichier de traduction (à moins d'utiliser une intersection (<code>typeof frLocales &amp; typeof enLocales</code>) plutôt qu'une union pour autoriser toutes les clés, comme <code>"Oh, vraiment ?"</code> présente seulement dans <code>en.json</code>)</li>
</ul>
<img src="https://media.giphy.com/media/DfbpTbQ9TvSX6/giphy.gif" alt="mic-drop" style="width:300px;margin:20px auto;display:block">]]></content:encoded>
            <category>TypeScript</category>
        </item>
        <item>
            <title><![CDATA[Nest : Le framework Node.js qu'il nous fallait]]></title>
            <link>https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait</link>
            <guid>https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait</guid>
            <pubDate>Fri, 03 Aug 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Nest ne vous a probablement pas échappé si vous faites de la veille technique... Ou peut-être que si. Après tout, 0 jour s'est écoulé depuis la sortie d'un nouveau framework JavaScript 😁. Mais alors pourquoi prendrait-on la peine d'en découvrir un de plus ?]]></description>
            <content:encoded><![CDATA[<p><a href="https://nestjs.com/" target="_blank" rel="noopener noreferrer">Nest</a> ne vous a probablement pas échappé si vous faites de la veille technique... Ou peut-être que si. Après tout, <a href="https://dayssincelastjavascriptframework.com/" target="_blank" rel="noopener noreferrer">0 jour</a> s'est écoulé depuis la sortie d'un nouveau framework JavaScript 😁. Mais alors pourquoi prendrait-on la peine d'en découvrir <strong>un de plus</strong> ?</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="introduction">Introduction<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#introduction" class="hash-link" aria-label="Lien direct vers Introduction" title="Lien direct vers Introduction">​</a></h2>
<p>Avec l'essor fulgurant qu'a connu le développement web ces 10 dernières années, l'environnement <em>frontend</em> a considérablement évolué : l'apparition de frameworks et <em>libs</em> comme <a href="https://angular.io/" target="_blank" rel="noopener noreferrer">Angular</a>, <a href="https://reactjs.org/" target="_blank" rel="noopener noreferrer">React</a>, ou <a href="https://vuejs.org/" target="_blank" rel="noopener noreferrer">Vue.js</a>, ont permis aux développeurs d'être plus productifs, tout en construisant des applications plus volumineuses et élégantes, sans que leurs performances ne soient lésées.</p>
<p>Dans l'environnement <em>backend</em>, cependant, malgré un écosystème <a href="http://www.modulecounts.com/" target="_blank" rel="noopener noreferrer">gigantesque</a>, de puissants outils et une communauté pro-active, un problème persiste : <strong>comment architecturer nos applications ?</strong></p>
<img src="https://media.giphy.com/media/dXICCcws9oxxK/giphy.gif" alt="stark" style="width:450px;margin:20px auto;display:block">
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="lexistant">L'existant<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#lexistant" class="hash-link" aria-label="Lien direct vers L'existant" title="Lien direct vers L'existant">​</a></h2>
<p><a href="http://expressjs.com/" target="_blank" rel="noopener noreferrer">Express</a> est le plus poulaire des frameworks web Node.js. Il est aussi le plus <em>unopinionated</em> (sic), soit celui qui laisse le plus de choix aux développeurs en terme d'architecture applicative. Malheureusement, <em><strong>trop</strong> de choix</em> entraîne souvent la prise d'<em><strong>aucune</strong> (bonne) décision</em>.</p>
<p><em>La plupart des faits suivants concernent aussi Hapi, Koa ou Fastify.</em></p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="contrôleurs">Contrôleurs<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#contr%C3%B4leurs" class="hash-link" aria-label="Lien direct vers Contrôleurs" title="Lien direct vers Contrôleurs">​</a></h3>
<p>Dans un projet Express "traditionnel", il est fréquent de voir des contrôleurs ressemblant à cela :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">ctrl app </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> express</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access maybe-class-name" style="color:#d73a49">Router</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/companies/:id'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">req</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> res</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token maybe-class-name">Companies</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">findById</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">req</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">params</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">id</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">err</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> company</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">err</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">company</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>On en trouve des similaires, parfois par centaines, agrégés dans des arborescences de fichiers construites totalement arbitrairement.</p>
<p>En l'état, ce contrôleur est pénible à tester. On peut extraire son callback dans une <code>class</code> dédiée, puis améliorer sa lisibilité en utilisant <code>async/await</code> et une version <em>promisified</em> de <code>findById</code> :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">ctrl app </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> express</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access maybe-class-name" style="color:#d73a49">Router</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/companies/:id'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> companiesController</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">getById</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// companies-controller.js</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CompaniesController</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getById</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">req</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> res</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> company </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> </span><span class="token maybe-class-name">Companies</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">findById</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">req</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">params</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">exec</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">company</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><em>La gestion des erreurs est ignorée pour la simplicité des exemples.</em></p>
<p>C'est mieux ! Le contrôleur est plus facilement testable. On évite aussi le <em>callback hell</em>.<br>
<!-- -->Pour autant, est-ce <strong>suffisant</strong> ? Du point de vue de la testabilité et du découplage, notre code souffre toujours de la présence de <code>req</code> et <code>res</code> (dans une moindre mesure, <code>app</code>).</p>
<p><strong>Avec Nest</strong>, voici à quoi ressemble un contrôleur équivalent :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/companies/:id'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">getById</span><span class="token punctuation" style="color:#393A34">(</span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Param</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'id'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> companyId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> Companies</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">findById</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">companyId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">exec</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>🔥 <em>Exit</em> le couplage fort à Express (<code>req</code>, <code>res</code>, <code>app</code>) et le <em>mocking</em> qui l'accompagnait dans les tests unitaires. Une simple fonction, facilement testable, indépendante de toute couche de transport (HTTP, WebSocket, ...), retournant une valeur synchrone ou asynchrone (<code>Promise</code>, <code>Observable</code>) 🎉.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="middlewares">Middlewares<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#middlewares" class="hash-link" aria-label="Lien direct vers Middlewares" title="Lien direct vers Middlewares">​</a></h3>
<p>Si l'on souhaite exécuter avant notre contrôleur des actions assez simples telles que :</p>
<ul>
<li>L'authentification de l’émetteur de la requête,</li>
<li>Du <em>logging</em>,</li>
<li>La validation des données d'entrée,</li>
<li>La transformation des données d'entrée,</li>
</ul>
<p>La solution <em>de facto</em> dans une application Express est le <strong>middleware</strong> : une fonction exécutée entre l'étape de <em>routing</em> et le contrôleur.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="express-middlewares" src="https://vinceops.me/assets/images/express-middlewares-d15cf6b48d42cb29ea775cbceb232c15.png" width="661" height="226" class="img_BhpN"><br>
<em>Dans les faits, un middleware peut interrompre un cycle Requête-Réponse en retournant une réponse.</em></p></div>
<p>Ce qui peut se traduire comme ceci :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">ctrl app </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> express</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access maybe-class-name" style="color:#d73a49">Router</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string" style="color:#e3116c">'/companies/:id'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// router-level middlewares</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">fnAuthenticate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fnLog</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fnValidate</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// controller : fait partie de la série</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  companiesController</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">createCompany</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>On peut bien sûr en exécuter <strong>après</strong> un contrôleur. Et il existe aussi des middlewares spéciaux permettant la gestion des erreurs HTTP (<code>404</code>, <code>500</code>, ...).</p>
<p>Par conséquent, dans bien des projets, on confie aux middlewares : l'authentification, le <em>logging</em>, la transformation et la validation des données d'entrée/sortie, la gestion des erreurs, ... 🤔<br>
<strong>Tout va bien</strong> ! Express <a href="http://expressjs.com/en/guide/using-middleware.html" target="_blank" rel="noopener noreferrer">est décrit</a> comme un framework de routing/middlewares dont les applications sont essentiellement des séries de Middlewares. Il n'y a donc rien d'anormal à ce que toute l'application soit construite comme telle... Pour autant, est-ce <strong>suffisant</strong> ?</p>
<p>❔ Quid de l'évolutivité, de la testabilité et de la maintenabilité d'une telle application ? Quelles meilleures pratiques suivre ? Faut-il les définir en interne et s'assurer que chaque nouveau collaborateur les applique ?</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="nestjs">NestJS<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#nestjs" class="hash-link" aria-label="Lien direct vers NestJS" title="Lien direct vers NestJS">​</a></h2>
<p>Et la question fatidique... Qu'apporte réellement Nest en terme de <strong>productivité</strong>, de <strong>maintenabilité</strong>, de <strong>testabilité</strong> et d'<strong>architecture</strong> ?</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="typescript">Typescript<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#typescript" class="hash-link" aria-label="Lien direct vers Typescript" title="Lien direct vers Typescript">​</a></h3>
<p>Conçu <em>avec</em> TypeScript <em>pour</em> des applications TypeScript, Nest exploite et apporte toute la puissance du langage (que j'ai longuement présenté <a href="https://vinceops.me/2018/04/22/typescript-partie-2-3-pourquoi-ladopter/" target="_blank" rel="noopener noreferrer">ici</a>), y compris toutes les fonctionnalités d'<code>ES2015</code>, <code>ES2016</code> et <code>ES2017</code>. De fait, Node.js v8.9+ est <a href="https://node.green/" target="_blank" rel="noopener noreferrer">recommandé</a> pour un support complet. Sinon, transpilez vers une <code>target</code> plus ancienne.</p>
<blockquote>
<p>Bien qu'il soit possible de développer une application Nest avec JavaScript et Babel, il est recommandé d'utiliser TypeScript pour une expérience optimale.<br>
<!-- -->🧙 "<strong><em>Types are priceless</em></strong>" - Kamil Myśliwiec</p>
</blockquote>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="modularité">Modularité<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#modularit%C3%A9" class="hash-link" aria-label="Lien direct vers Modularité" title="Lien direct vers Modularité">​</a></h3>
<p>La philosophie du framework est fidèle aux principes de conception <a href="https://en.wikipedia.org/wiki/SOLID" target="_blank" rel="noopener noreferrer">SOLID</a> ainsi qu'à la <a href="https://en.wikipedia.org/wiki/Separation_of_concerns" target="_blank" rel="noopener noreferrer">séparation des intérêts</a>. À ce titre, le code d'une application Nest se découpe généralement en <strong>Modules</strong> constitués de <strong>Composants</strong> ou <em>providers</em> et éventuellement de <strong>Contrôleurs</strong>.</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Module</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  imports</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">OAuthModule</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  controllers</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">AuthController</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  providers</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">AuthService</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  exports</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">AuthService</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">AuthModule</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Les développeurs Angular noteront la proximité syntaxique avec <code>@NgModule</code>.</p></div></div>
<p>Cette séparation du code par tâche logique (ou métier) en <a href="https://docs.nestjs.com/modules" target="_blank" rel="noopener noreferrer">modules</a>  encourage l'isolation et la réutilisation des composants de l'application.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="injection-de-dépendances">Injection de dépendances<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#injection-de-d%C3%A9pendances" class="hash-link" aria-label="Lien direct vers Injection de dépendances" title="Lien direct vers Injection de dépendances">​</a></h3>
<p>Les <em>controllers</em> et <em>providers</em> peuvent injecter (via leur constructeur) d'autres <em>providers</em> grâce au conteneur d'<strong>injection de dépendances</strong> de Nest.</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Controller</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'auth'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">AuthController</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// this.authService est assigné dans le constructeur</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> authService</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> AuthService</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Il est aussi possible de définir des <a href="https://docs.nestjs.com/fundamentals/custom-providers" target="_blank" rel="noopener noreferrer"><em>providers</em> personnalisés</a> (et <a href="https://docs.nestjs.com/fundamentals/async-providers" target="_blank" rel="noopener noreferrer">asynchrones</a>), afin d'injecter des bibliothèques et modules npm, des valeurs calculées dynamiquement... Par exemple :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// user-service.provider.ts</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">USER_SERVICE</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'UserService'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> UserServiceProvider </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  provide</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">USER_SERVICE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  useClass</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> FirebaseService</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Nest injecte les dépendances grâce à un <em>token</em> : on utilise <code>USER_SERVICE</code> pour identifier notre service de gestion des utilisateurs.<br>
<code>@Inject()</code> indique à Nest <em>quoi</em> injecter, quand l'annotation de type ne suffit pas à l'identifier :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// auth.service.ts : Injection + Typage par Interface</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Inject</span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">USER_SERVICE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> userService</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> IUserService</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Ici, on admet évidemment que <code>FirebaseService</code> implémente l'interface <code>IUserService</code> et qu'<code>UserServiceProvider</code> a été ajouté aux <code>providers</code> d'<code>AuthModule</code>.<br>
<!-- -->👍 <code>AuthService</code> est désormais découplé : il dépend d'une implémentation d'<code>IUserService</code> mais ignore laquelle.</p>
<blockquote>
<p>Ce n'est pas la façon la plus élégante de régler ce problème, mais elle a le mérite de ne pas trop alourdir l'article. Si le sujet vous intéresse, n'hésitez pas à m'en faire part.</p>
</blockquote>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="testabilité">Testabilité<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#testabilit%C3%A9" class="hash-link" aria-label="Lien direct vers Testabilité" title="Lien direct vers Testabilité">​</a></h3>
<p>Le test des composants est très largement facilité par :</p>
<ul>
<li>L'injection de dépendance : toute dépendance peut être facilement simulée (<em>mock</em>) avant d'être passée en paramètre d'un constructeur.</li>
<li>L'aspect <em>framework agnostic</em> de Nest : il n'y a pas (ou rarement) besoin de <em>mock</em> des objets propres à Express (<code>req</code>, <code>res</code>...) et toute dépendance externe (package npm, etc) peut aussi être injectée à l'aide d'un <a href="https://docs.nestjs.com/fundamentals/custom-providers" target="_blank" rel="noopener noreferrer"><em>custom provider</em></a>.</li>
</ul>
<p>Le test de l'application (End-to-End) est quelque peu facilité par la modularité de celle-ci. En effet, Nest fournit un <a href="https://docs.nestjs.com/fundamentals/e2e-testing" target="_blank" rel="noopener noreferrer"><code>TestingModule</code></a> dans lequel on importe un à plusieurs modules pour lancer notre application.
Grâce (encore) aux <em>custom providers</em>, on peut, au besoin, remplacer certains composants : par exemple, pour tester différentes implémentations d'une interface <code>ILambdaService</code> (AWS Lambda, Google Cloud Functions, ...) <strong>ou</strong> deux états d'une même implémentation (service disponible et service hors-ligne/en maintenance).</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="gestion-des-erreurs">Gestion des erreurs<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#gestion-des-erreurs" class="hash-link" aria-label="Lien direct vers Gestion des erreurs" title="Lien direct vers Gestion des erreurs">​</a></h3>
<p>Autre fonctionnalité, les <strong>filtres d'exception</strong> permettent la gestion des exceptions lancées par l'application. Dans un contrôleur Nest, aucun <code>return res.status(404).end()</code>, ni même d'import du brave <a href="https://www.npmjs.com/package/boom" target="_blank" rel="noopener noreferrer">boom</a>. Le framework inclut des classes <code>NotFoundException</code>, <code>ForbiddenException</code>, etc, toutes filles de <code>HttpException</code>.</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">findOne</span><span class="token punctuation" style="color:#393A34">(</span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Param</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'id'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> userId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> user </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">userService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">findOne</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> userId </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">user</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">throw</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">NotFoundException</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> user</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Les <em>exception filters</em> sont exécutés en fin de chaîne, pour les types d'exceptions qu'on leur attribue (si aucun type n'est attribué, alors le filtre est exécuté pour chaque exception). C'est dans la méthode <code>catch</code> du filtre que l'on va retourner une réponse au client.</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Les Exception Filters peuvent injecter des dépendances.</p></div></div>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// filtre pour : NotFoundException et ForbiddenException</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Catch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">NotFoundException</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ForbiddenException</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">HttpExceptionFilter</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">ExceptionFilter</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> loggerService</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> LoggerService</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">catch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">exception</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> HttpException</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> host</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ArgumentsHost</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">loggerService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">warn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Uncaught exception'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> exception</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// dans le cas d'un cycle Requête-Réponse via HTTP</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> res </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> host</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">switchToHttp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getResponse</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// par exemple :</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">status</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">exception</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getStatus</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="pipes">Pipes<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#pipes" class="hash-link" aria-label="Lien direct vers Pipes" title="Lien direct vers Pipes">​</a></h3>
<p>Les Pipes permettent la transformation et/ou la validation d'une donnée d'entrée. Prenons l'exemple d'un contrôleur permettant l'écriture d'un commentaire dans un article :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Post</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'article/:articleId/comment'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">createComment</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Param</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'articleId'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> articleId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Body</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ValidationPipe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> whitelist</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> comment</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> CreateCommentDto</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">articleService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">addComment</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">comment</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Il est facile de créer ses propres Pipes, mais on utilise ici un <code>Pipe</code> intégré : <code>ValidationPipe</code>. Il effectue la validation d'une donnée passée en entrée, en fonction d'un modèle défini en amont (ici, <code>CreateCommentDto</code>), à l'aide du paquet <a href="https://github.com/typestack/class-validator" target="_blank" rel="noopener noreferrer"><code>class-validator</code></a> et de ses précieux décorateurs :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CreateCommentDto</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">IsString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">IsNotEmpty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">MinLength</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  content</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">IsString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">IsNotEmpty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">IsEmail</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  author</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Par défaut, si le corps de la requête (d'où le décorateur <code>@Body()</code>) ne correspond pas au modèle attendu, <code>ValidationPipe</code> interrompt le cycle Requête-Réponse pour lancer une <code>BadRequestException</code> (<em>aka Error 400</em>).</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Les Pipes peuvent injecter des dépendances</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="interceptors">Interceptors<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#interceptors" class="hash-link" aria-label="Lien direct vers Interceptors" title="Lien direct vers Interceptors">​</a></h3>
<p>Exécutés avant <strong>et</strong> après un contrôleur, les Interceptors peuvent, entre autres :</p>
<ul>
<li>Transformer la valeur (ou l'exception) retournée par un contrôleur (avant de l'envoyer)</li>
<li>Empêcher l'exécution d'un contrôleur (en répondant à sa place) sous certaines conditions</li>
</ul>
<p>Cette manipulation de flux est possible grâce au puissant <a href="http://reactivex.io/rxjs/" target="_blank" rel="noopener noreferrer">RxJS</a>.</p>
<p>Voici un exemple d'intercepteur (tiré de la documentation de Nest) qui interrompt le cycle Requête-Réponse en émettant une erreur si aucune valeur n'est émise sur le flux (nommé ici <code>call$</code>) sous 5 secondes (cf. <a href="http://reactivex.io/documentation/operators/timeout.html" target="_blank" rel="noopener noreferrer">timeout</a>).</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Injectable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">TimeoutInterceptor</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">NestInterceptor</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">intercept</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    context</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ExecutionContext</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    call$</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Observable</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">any</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Observable</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">any</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> call$</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pipe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">timeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">5000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Les Interceptors peuvent injecter des dépendances.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="guards">Guards<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#guards" class="hash-link" aria-label="Lien direct vers Guards" title="Lien direct vers Guards">​</a></h3>
<p>Un Guard détermine si le contrôleur <em>gardé</em> doit traiter la requête entrante. Dans le cas contraire, une exception <code>ForbiddenException</code> (<em>aka Error 403</em>) est lancée.
Les guards sont exécutés après les <a href="https://docs.nestjs.com/middleware" target="_blank" rel="noopener noreferrer">Middlewares</a> et les <a href="https://docs.nestjs.com/pipes" target="_blank" rel="noopener noreferrer">Pipes</a>, mais avant les <a href="https://docs.nestjs.com/interceptors" target="_blank" rel="noopener noreferrer">Interceptors</a>.</p>
<p>Ils permettent de résumer à un ou deux décorateurs le contrôle d'accès à un contrôleur (ou à toute une classe <code>Controller</code>, ou à toute l'application) :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Post</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">UseGuards</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">RolesGuard</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Roles</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'admin'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createCompany</span><span class="token punctuation" style="color:#393A34">(</span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Body</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> createCompanyDto</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> CreateCompanyDto</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">companyService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">createCompanyDto</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Dans cet exemple, on a créé un décorateur <code>Roles</code> qui ajoute de la <a href="https://github.com/rbuckton/reflect-metadata" target="_blank" rel="noopener noreferrer">metadata</a> à notre méthode <code>createCompany</code> :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> ReflectMetadata </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@nestjs/common'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">Roles</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">roles</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ReflectMetadata</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'roles'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> roles</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le guard <code>RolesGuard</code> a accès à <code>createCompany</code> et peut lire cette metadata. Ainsi, les utilisateurs n'ayant pas le rôle <code>admin</code>  se verront refuser le traitement de leur requête :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Injectable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">RolesGuard</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">CanActivate</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> reflector</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Reflector</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">canActivate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ExecutionContext</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> roles </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">reflector</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-function function" style="color:#d73a49">get</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name builtin">string</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">[</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">]</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'roles'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getHandler</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ... logique d'autorisation</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Bien sûr, on peut imaginer toutes sortes de Guards : utiliser une <em>strategy</em> <a href="http://www.passportjs.org/" target="_blank" rel="noopener noreferrer">passportjs</a>, dépendre d'une base de données ou d'un service tiers, etc.</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Les Guards peuvent injecter des dépendances et être asynchrones.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="outils-et-intégrations">Outils et intégrations<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#outils-et-int%C3%A9grations" class="hash-link" aria-label="Lien direct vers Outils et intégrations" title="Lien direct vers Outils et intégrations">​</a></h3>
<p>Parce qu'il est impossible de faire le tour complet de Nest en un seul article, mais qu'ils sont quand même un argument majeur du framework, notez qu'il existe des intégrations TypeScript et outils pour :</p>
<ul>
<li><a href="https://docs.nestjs.com/techniques/database" target="_blank" rel="noopener noreferrer">ORM</a> (<a href="http://typeorm.io/" target="_blank" rel="noopener noreferrer">TypeORM</a>, <a href="http://docs.sequelizejs.com/" target="_blank" rel="noopener noreferrer">Sequelize</a>) et <a href="https://docs.nestjs.com/techniques/mongodb" target="_blank" rel="noopener noreferrer">ODM</a> (<a href="http://mongoosejs.com/" target="_blank" rel="noopener noreferrer">Mongoose</a>)</li>
<li><a href="https://docs.nestjs.com/graphql/quick-start" target="_blank" rel="noopener noreferrer">GraphQL</a> (Apollo)</li>
<li><a href="https://docs.nestjs.com/recipes/swagger" target="_blank" rel="noopener noreferrer">OpenAPI</a> (Swagger)</li>
<li><a href="https://docs.nestjs.com/websockets/gateways" target="_blank" rel="noopener noreferrer">Websockets</a> (<a href="https://socket.io/" target="_blank" rel="noopener noreferrer">socket.io</a>)</li>
<li><a href="https://docs.nestjs.com/microservices/basics" target="_blank" rel="noopener noreferrer">Microservices</a> (TCP, Redis Pub/Sub, MQTT, gRPC, etc.)</li>
<li><a href="https://docs.nestjs.com/techniques/authentication" target="_blank" rel="noopener noreferrer">L'authentification</a> (<a href="http://www.passportjs.org/" target="_blank" rel="noopener noreferrer">Passport</a>)</li>
</ul>
<p><em>Liste non exhaustive</em></p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="conclusion">Conclusion<a href="https://vinceops.me/nest-framework-nodejs-qu-il-nous-fallait#conclusion" class="hash-link" aria-label="Lien direct vers Conclusion" title="Lien direct vers Conclusion">​</a></h2>
<p>En résumé, <strong>Nest est</strong> : un cadre structurant encourageant les bonnes pratiques, <em>framework agnostic</em>, portant une architecture modulaire, offrant de l'injection de dépendances et de puissants composants tels que les Pipes et Interceptors, accompagné d'intégrations élégantes, le tout écrit avec/pour TypeScript.</p>
<p><em>Bien que ça n'ait pas été abordé, Nest permet aussi la création d'application de type CLI, script, <a href="https://docs.nestjs.com/execution-context" target="_blank" rel="noopener noreferrer">etc</a>.</em></p>]]></content:encoded>
            <category>nest</category>
            <category>node.js</category>
            <category>typescript</category>
            <category>testing</category>
            <category>productivité</category>
        </item>
        <item>
            <title><![CDATA[TypeScript - 3/3 : Installation & Migration]]></title>
            <link>https://vinceops.me/typescript-3-installation-migration</link>
            <guid>https://vinceops.me/typescript-3-installation-migration</guid>
            <pubDate>Sun, 22 Apr 2018 12:02:00 GMT</pubDate>
            <description><![CDATA[Suite de la deuxième partie du dossier.]]></description>
            <content:encoded><![CDATA[<p><em>Suite de la <a href="https://vinceops.me/typescript-2-pourquoi-l-adopter">deuxième partie</a> du dossier.</em></p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="installation">Installation<a href="https://vinceops.me/typescript-3-installation-migration#installation" class="hash-link" aria-label="Lien direct vers Installation" title="Lien direct vers Installation">​</a></h2>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">npm install -g typescript</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le paquet <a href="https://www.npmjs.com/package/typescript" target="_blank" rel="noopener noreferrer">typescript</a> contient le compilateur <code>tsc</code> découvert dans la première partie du dossier.</p>
<p>L'installation du paquet <a href="https://www.npmjs.com/package/tslint" target="_blank" rel="noopener noreferrer">tslint</a> est aussi conseillée (globale, ou locale à votre projet).</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Depuis la date d'écriture de cet article, <code>tslint</code> a été déprécié au profit de <a href="https://eslint.org/" target="_blank" rel="noopener noreferrer">eslint</a>. Pour les projets TypeScript, il existe tout une suite de plugin eslint officiel.</p></div></div>
<p>Dans le répertoire du projet, sont requis (<em>recommandés</em>) :</p>
<ul>
<li>Un fichier <code>tsconfig.json</code>, généré avec la commande <code>tsc --init</code> ou récupéré d'un projet type <em>boilerplate</em>.</li>
<li>Un fichier <code>tslint.json</code>, généré avec la commande <code>tslint --init</code> ou récupéré d'un projet type <em>boilerplate</em>. Pour "<em>linter</em>" le projet, on exécute <code>tslint -p .</code> à la racine du projet.</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p><code>-p</code> indique l'emplacement de <code>tsconfig.json</code> (<a href="https://palantir.github.io/tslint/usage/cli/" target="_blank" rel="noopener noreferrer">détails</a>)</p></div></div>
<ul>
<li>Un éditeur de code avec un support décent de TypeScript : VSCode, WebStorm, ...</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="intégration">Intégration<a href="https://vinceops.me/typescript-3-installation-migration#int%C3%A9gration" class="hash-link" aria-label="Lien direct vers Intégration" title="Lien direct vers Intégration">​</a></h3>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="frontend">Frontend<a href="https://vinceops.me/typescript-3-installation-migration#frontend" class="hash-link" aria-label="Lien direct vers Frontend" title="Lien direct vers Frontend">​</a></h4>
<p>Il existe des configurations/plugins pour les principaux outils de transpilation et <em>packaging</em>:</p>
<ul>
<li>Avec <a href="https://babeljs.io/blog/2017/09/12/planning-for-7.0" target="_blank" rel="noopener noreferrer">Babel 7</a> et le <em>preset</em> <a href="https://github.com/babel/babel/tree/master/packages/babel-preset-typescript" target="_blank" rel="noopener noreferrer">babel-preset-typescript</a></li>
<li>Avec Webpack et <a href="https://github.com/TypeStrong/ts-loader" target="_blank" rel="noopener noreferrer">ts-loader</a> ou <a href="https://github.com/s-panferov/awesome-typescript-loader" target="_blank" rel="noopener noreferrer">awesome-typescript-loader</a>; d'avantage d'informations dans la <a href="https://www.typescriptlang.org/docs/handbook/integrating-with-build-tools.html" target="_blank" rel="noopener noreferrer">documentation officielle</a></li>
<li>Avec Rollup et <a href="https://github.com/ezolenko/rollup-plugin-typescript2" target="_blank" rel="noopener noreferrer">rollup-plugin-typescript2</a></li>
<li>Pour Browserify, Grunt, Gulp, référez-vous à la <a href="https://www.typescriptlang.org/docs/handbook/integrating-with-build-tools.html" target="_blank" rel="noopener noreferrer">documentation officielle</a></li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="backend-et-scripts">Backend et scripts<a href="https://vinceops.me/typescript-3-installation-migration#backend-et-scripts" class="hash-link" aria-label="Lien direct vers Backend et scripts" title="Lien direct vers Backend et scripts">​</a></h4>
<p><a href="https://github.com/TypeStrong/ts-node" target="_blank" rel="noopener noreferrer">ts-node</a> accélère légèrement le processus de développement, en permettant à node de charger des modules TypeScript (transpilés en mémoire lors de l'import).</p>
<p>Il peut être utilisé en ligne de commande, pour exécuter directement des fichiers TypeScript :</p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">ts-node index.ts</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>ou bien exécuté comme module, dans un point d'entrée JavaScript classique (<code>node index.js</code>) :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'ts-node'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">register</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// on peut ensuite importer un fichier TypeScript (./src/index.ts)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'./src/index'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="migration">Migration<a href="https://vinceops.me/typescript-3-installation-migration#migration" class="hash-link" aria-label="Lien direct vers Migration" title="Lien direct vers Migration">​</a></h2>
<p>L'intégration progressive de TypeScript dans un projet JavaScript existant est un bon exercice pour adopter le langage.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="adapter-le-code-existant">Adapter le code existant<a href="https://vinceops.me/typescript-3-installation-migration#adapter-le-code-existant" class="hash-link" aria-label="Lien direct vers Adapter le code existant" title="Lien direct vers Adapter le code existant">​</a></h3>
<ul>
<li>Activer <code>allowJs</code> (<code>tsconfig.json</code>) afin que le code existant soit intégré au code généré par <code>tsc</code>.</li>
<li>Procéder à la modification du code, fichier par fichier, à l'aide de l'annotation <code>// @ts-check</code>.</li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="ts-check">@ts-check<a href="https://vinceops.me/typescript-3-installation-migration#ts-check" class="hash-link" aria-label="Lien direct vers @ts-check" title="Lien direct vers @ts-check">​</a></h4>
<p><code>tsc</code> effectue l'analyse statique du code JavaScript contenant le commentaire <code>// @ts-check</code>.
Il est aussi possible d'utiliser l'option <code>--checkJs</code> (CLI de <code>tsc</code>, ou dans <code>tsconfig.json</code>) pour analyser <strong>tous</strong> les fichiers JavaScript passés en entrée.</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Si vous optez pour <code>checkJs</code>, utilisez <code>@ts-nocheck</code> pour exclure certains fichiers JavaScript de l'analyse. Pour exclure seulement certaines lignes de code, utilisez <code>@ts-ignore</code> (avant chaque ligne).</p></div></div>
<p>Mieux encore : TypeScript peut <em>aussi</em> utiliser votre <strong>JSDoc</strong> pour <a href="https://github.com/Microsoft/TypeScript/wiki/Type-Checking-JavaScript-Files" target="_blank" rel="noopener noreferrer">trouver des erreurs</a> dans votre code.</p>
<p>Voici un exemple, <code>normalize-name.js</code> :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// @ts-check</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@param</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">string</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment parameter" style="color:#999988;font-style:italic">name</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> Name to be normalized</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> *</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@return</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">string</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> Normalized name.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">normalizeName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">trim</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toUpperCase</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Erreur : 5 n'est pas une string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">normalizeName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Erreur : normalizeName retourne une string (calcul impossible)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">normalizeName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'MiKe'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>À la compilation <code>tsc</code> renvoie les erreurs suivantes :</p>
<blockquote>
<p>❌ normalize-name.<strong>js</strong>(13,15): error TS2345: Argument of type '5' is not assignable to parameter of type 'string'.<br>
<!-- -->❌ normalize-name.<strong>js</strong>(15,15): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.</p>
</blockquote>
<p>Par contre, dans le code ci-dessus, passer <code>undefined</code> à <code>normalizeName</code> n'est pas signalé comme une erreur par <code>tsc</code>. En effet, il s'agit de <strong>JavaScript</strong>, non de TypeScript. Il en va de même avec <strong>TypeScript</strong>, si l'option <code>strict</code> n'est pas activée : <code>tsc</code> transpile l'instruction sans nous avertir.</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">normalizeName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword nil" style="color:#00009f">undefined</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Cette instruction provoquera l'erreur <code>TypeError: Cannot read property 'trim' of undefined</code> à <strong>l'exécution</strong>. Une erreur de <em>runtime</em> facilement évitable avec TypeScript <strong>et</strong> le mode <code>strict</code>.</p>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="changement-de-lextension-js-en-ts">Changement de l'extension "js" en "ts"<a href="https://vinceops.me/typescript-3-installation-migration#changement-de-lextension-js-en-ts" class="hash-link" aria-label="Lien direct vers Changement de l'extension &quot;js&quot; en &quot;ts&quot;" title="Lien direct vers Changement de l'extension &quot;js&quot; en &quot;ts&quot;">​</a></h4>
<p>En effet, avec l'option <code>"strict"</code> à <code>true</code> dans <code>tsconfig.json</code>, on obtient l'erreur suivante en tentant de transpiler ce code TypeScript (<code>normalize-name.ts</code>, notez l'extension <strong><code>.ts</code></strong>) :</p>
<blockquote>
<p>❌ normalize-name.<strong>ts</strong>(13,15): error TS2345: Argument of type 'undefined' is not assignable to parameter of type 'string'</p>
</blockquote>
<p>Pour un code TypeScript (<strong>.ts</strong>, <strong>.tsx</strong>), <code>tsc</code> tient compte de la configuration établie dans <code>tsconfig.json</code>.</p>
<p>Par conséquent, l'adoption progressive (fichier par fichier) peut se faire en deux temps. D'abord à l'aide de <code>@ts-check</code>; ensuite en changeant l'extension <code>js</code> du fichier en <code>ts</code>.</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>L'option <code>sourceMap</code> permet de générer les <strong>source maps</strong> correspondant au code transpilé.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="packages-npm-et-imports">Packages NPM et Imports<a href="https://vinceops.me/typescript-3-installation-migration#packages-npm-et-imports" class="hash-link" aria-label="Lien direct vers Packages NPM et Imports" title="Lien direct vers Packages NPM et Imports">​</a></h3>
<p>Pour les packages NPM importés dans le projet, <code>tsc</code> s'attend à ce qu'ils possèdent un <a href="http://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html" target="_blank" rel="noopener noreferrer">fichier de déclaration</a>. Certains packages NPM en sont déjà équipés : c'est le cas idéal. Sinon il reste deux possibilités :</p>
<ul>
<li>Installer les packages <a href="https://github.com/DefinitelyTyped/DefinitelyTyped" target="_blank" rel="noopener noreferrer">DefinitelyTyped</a> correspondants.  Il en existe pour la plupart des packages (<code>@types/node</code>, <code>@types/express</code>, <code>@types/lodash</code>, <code>@types/jest</code>, ...).</li>
<li>Créer des déclarations vides (<em>stubs</em>) de ces packages, pour autoriser leur import sans qu'ils soient signalés comme inconnus (<em>"Could not find a declaration file for module '...' [...]"</em>) :</li>
</ul>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">declare</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">module</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'nom-du-module'</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>C'est une solution de "secours" lorsqu'aucun package <code>@types</code> correspondant n'est disponible, ou qu'il n'est pas à jour. Vous pouvez aussi définir vous-même la déclaration du package et <a href="http://definitelytyped.org/guides/contributing.html" target="_blank" rel="noopener noreferrer">la partager</a> avec la communauté.</p>
<p>Pour permettre l'import de fichiers JSON (<code>import * as fileContent from './file.json'</code>) :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">declare</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">module</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'*.json'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Pour générer les fichiers de déclaration de votre projet (par exemple, si c'est un projet open-source), activez l'option <code>declaration</code>.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="conclusion">Conclusion<a href="https://vinceops.me/typescript-3-installation-migration#conclusion" class="hash-link" aria-label="Lien direct vers Conclusion" title="Lien direct vers Conclusion">​</a></h3>
<p>Vous trouverez d'avantage de détails sur la migration depuis JavaScript dans la <a href="https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html" target="_blank" rel="noopener noreferrer">documentation officielle</a>.</p>
<p>Une fois n'est pas coutume, j'insiste sur l'importance  de l'option <code>strict</code>. Comme le précise la <a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html" target="_blank" rel="noopener noreferrer">documentation</a>, elle entraîne l'activation de plusieurs règles (dont <code>noImplicitAny</code> ) qui rendent <code>tsc</code> très exigeant sur la qualité (et le typage) de votre code mais permettent de tirer le meilleur profit de TypeScript.</p>]]></content:encoded>
            <category>typescript</category>
        </item>
        <item>
            <title><![CDATA[TypeScript - 2/3 : Pourquoi l'adopter]]></title>
            <link>https://vinceops.me/typescript-2-pourquoi-l-adopter</link>
            <guid>https://vinceops.me/typescript-2-pourquoi-l-adopter</guid>
            <pubDate>Sun, 22 Apr 2018 12:01:00 GMT</pubDate>
            <description><![CDATA[Suite de la première partie du dossier.]]></description>
            <content:encoded><![CDATA[<p><em>Suite de la <a href="https://vinceops.me/typescript-1-presentation/">première partie</a> du dossier.</em></p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="pourquoi-ladopter">Pourquoi l'adopter<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#pourquoi-ladopter" class="hash-link" aria-label="Lien direct vers Pourquoi l'adopter" title="Lien direct vers Pourquoi l'adopter">​</a></h2>
<p>Les articles présentant les avantages et inconvénients de TypeScript ne manquent pas sur la toile. J'aborde ici une liste <strong>non-exhaustive</strong> des points forts qui justifient que l'on s'intéresse au langage.</p>
<p>Deux citations d'Anders Hejlsberg au sujet de JavaScript, qui, au risque de sonner comme un <em>troll</em>, auront certainement le mérite de faire sourire les développeurs JavaScript expérimentés :</p>
<blockquote>
<p><strong>Erik Meijer</strong>: Vous insinuez que l'on ne peut pas écrire de grosses applications en JavaScript ?<br>
<strong>Anders Hejlsberg</strong>: Non, vous pouvez les écrire. Mais vous ne pouvez pas les maintenir.<br>
<a href="https://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2012/Panel-Web-and-Cloud-Programming" target="_blank" rel="noopener noreferrer">Lang.NEXT 2012</a></p>
</blockquote>
<p>Et plus récemment :</p>
<blockquote>
<p>Les très gros codes source JavaScript ont tendance à finir en "Lecture seule".<br>
<strong>Anders Hejlsberg</strong>, <a href="https://channel9.msdn.com/Events/Build/2016/B881" target="_blank" rel="noopener noreferrer">Microsoft Build 2016</a></p>
</blockquote>
<hr>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="avantages-du-typage">Avantages du Typage<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#avantages-du-typage" class="hash-link" aria-label="Lien direct vers Avantages du Typage" title="Lien direct vers Avantages du Typage">​</a></h3>
<p>Le typage, bien qu'optionnel, apporte de nombreux avantages, dont :</p>
<ul>
<li>L'analyse statique (sans exécution) du code</li>
<li>L'amélioration significative de la capacité à maintenir et réusiner (<em>refactor</em>) le code</li>
<li>Un code plus lisible et plus rapidement compréhensible (les annotations de type jouant aussi un rôle de documentation)</li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="analyse-statique">Analyse statique<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#analyse-statique" class="hash-link" aria-label="Lien direct vers Analyse statique" title="Lien direct vers Analyse statique">​</a></h4>
<p>TypeScript est accompagné de fichiers de <a href="http://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html" target="_blank" rel="noopener noreferrer"><strong>déclaration</strong></a> des API d'ES5, ES6, du DOM, etc. La plupart des packages (npm) majeurs contiennent aussi des fichiers de déclaration (sinon, on peut souvent les trouver dans les packages tiers, comme <code>@types/express</code>).
<code>tsc</code> est capable d'en tirer parti pour anticiper des erreurs éventuelles de programmation, au-delà de la simple analyse (élémentaire) inhérente aux règles du langage (comme, par exemple, l'impossibilité de multiplier deux <code>string</code>, ou de passer une <code>string</code> en argument d'une fonction attendant un <code>number</code>).</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> diacritics </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'diacritics'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">normalizeName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> diacritics</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">toLocalUpperCase</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">normalizeName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">undefined</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><code>tsc</code> (ou votre IDE, indirectement) signale une erreur à la ligne 4 :</p>
<blockquote>
<p>❌ error TS2551: Property 'toLocalUpperCase' does not exist on type 'string'. Did you mean 'toLocaleUpperCase'?</p>
</blockquote>
<p>Après correction, <code>tsc</code> signale une autre erreur, ligne 7 (seulement si le mode <code>strict</code> est activé) :</p>
<blockquote>
<p>❌ error TS2345: Argument of type 'undefined' is not assignable to parameter of type 'string'</p>
</blockquote>
<p>Ce qui marche avec les types basiques, ici, marche avec tous les types :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> _ </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'lodash'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> firstName</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> lastName</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> mike </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Mike'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Smith'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> partialMike </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-function function" style="color:#d73a49">pick</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">Person</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">,</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name keyword" style="color:#00009f">keyof</span><span class="token generic-function generic class-name"> Person</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mike</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'firstName'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'age'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>VS Code signale une erreur ligne 8, sur <code>'age'</code> :</p>
<blockquote>
<p>❌ <!-- -->error TS2345: Argument of type '"age"' is not assignable to parameter of type 'Many&lt;"firstName" | "lastName"&gt;'.</p>
</blockquote>
<p>La <strong>définition</strong> de <code>pick</code> dans <code>@types/lodash</code> spécifie que seules les propriétés listées dans le second paramètre de type  (<code>keyof Person</code>) sont acceptées (<a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html" target="_blank" rel="noopener noreferrer">présentation de keyof</a>). Ce morceau de code est donc "robuste" à toute évolution  de <code>Person</code> (propriété renommée, supprimée, etc.) et évite aussi certaines étourderies comme les fautes de frappe dans les noms de propriétés/méthodes..</p>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="refactoring">Refactoring<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#refactoring" class="hash-link" aria-label="Lien direct vers Refactoring" title="Lien direct vers Refactoring">​</a></h4>
<p>Le typage permet aux IDE de mieux nous servir. L'<em>autocompletion</em>, la propagation du renommage de méthodes, propriétés, variables, la fonctionnalité "Find usages" (ou "Find references")... Ces outils fonctionnent souvent bien mieux une fois la <em>codebase</em> typée.</p>
<p>Aussi, bien que cela soit de moins en moins marqué grâce à l'<a href="https://github.com/Microsoft/TypeScript/wiki/JavaScript-Language-Service-in-Visual-Studio" target="_blank" rel="noopener noreferrer">excellent support</a> d'ES6 par les IDE, le <em>refactoring</em> prend une autre ampleur grâce à l'analyse statique : on peut renommer une propriété, une méthode ou une variable, sans craindre d'induire des erreurs de <em>runtime</em> comme <code>TypeError: cannot read property 'x' of undefined</code>, ou encore <code>TypeError: x.y() is not a function</code>. En effet, la transpilation échoue si l'on tente d'accéder à une propriété/méthode/variable non définie.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="refactor-man" src="https://vinceops.me/assets/images/56-refactor-man-e8d79b556b4e2487f54d9f4d4c28471d.png" width="1200" height="1223" class="img_BhpN"></p></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="les-nouveautés-decmascript">Les nouveautés d'ECMAScript<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#les-nouveaut%C3%A9s-decmascript" class="hash-link" aria-label="Lien direct vers Les nouveautés d'ECMAScript" title="Lien direct vers Les nouveautés d'ECMAScript">​</a></h3>
<p>À l'heure où cet article est écrit, TypeScript 2.8 est vieux de seulement quelques semaines. Pourtant, on ne compte plus les <em>proposals</em> du comité de normalisation d'ECMAScript (<a href="https://github.com/tc39" target="_blank" rel="noopener noreferrer">TC39</a>) ayant été intégrées assez tôt dans le langage :</p>
<ul>
<li><a href="https://github.com/tc39/proposal-class-fields" target="_blank" rel="noopener noreferrer">Class fields</a> : Depuis toujours. TypeScript est un langage de programmation orienté objet (cf. section suivante).</li>
<li><a href="https://github.com/tc39/proposal-template-literal-revision" target="_blank" rel="noopener noreferrer">Template Strings</a> : TypeScript <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-4.html" target="_blank" rel="noopener noreferrer">1.4</a> <em>16/01/2015</em></li>
<li><a href="https://github.com/tc39/proposal-decorators" target="_blank" rel="noopener noreferrer">Decorators</a> : TypeScript <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-5.html" target="_blank" rel="noopener noreferrer">1.5</a> <em>20/07/2015</em></li>
<li><a href="https://github.com/tc39/ecmascript-asyncawait" target="_blank" rel="noopener noreferrer">async/await</a> : TypeScript <a href="http://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-7.html" target="_blank" rel="noopener noreferrer">1.7</a> <em>30/11/2015</em> (Node v4+, ES6), <a href="http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html" target="_blank" rel="noopener noreferrer">2.1</a> (ES3 / ES5, avec un polyfill pour <code>Promise</code>).</li>
<li><a href="https://github.com/tc39/proposal-object-rest-spread" target="_blank" rel="noopener noreferrer">Object Rest/Spread</a>: TypeScript <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html" target="_blank" rel="noopener noreferrer">2.1</a> <em>07/12/2016</em></li>
<li><a href="https://github.com/tc39/proposal-dynamic-import" target="_blank" rel="noopener noreferrer">Dynamic import</a> : TypeScript <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html" target="_blank" rel="noopener noreferrer">2.4</a> <em>27/06/2017</em></li>
<li><a href="https://github.com/tc39/proposal-optional-catch-binding" target="_blank" rel="noopener noreferrer">Optional catch clause</a> : TypeScript <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-5.html" target="_blank" rel="noopener noreferrer">2.5</a> <em>31/08/2017</em></li>
<li><a href="https://github.com/tc39/proposal-numeric-separator" target="_blank" rel="noopener noreferrer">Numeric separators</a> <!-- -->:TypeScript<!-- --> <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html" target="_blank" rel="noopener noreferrer">2.7</a> <em>31/01/2018</em></li>
<li>etc.</li>
</ul>
<p>On est aussi en mesure d'utiliser la plupart de ces fonctionnalités (et plus encore) avec <strong>Babel</strong>.  Cependant, il est impossible pour le moment (Babel 6+) d'intégrer du code TypeScript à votre chaîne de transpilation Babel. Il faudra donc attendre que <a href="https://babeljs.io/blog/2017/09/12/planning-for-7.0" target="_blank" rel="noopener noreferrer"><strong>Babel 7.0</strong></a> soit publiée ! &nbsp; 🎉</p>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>You can now use <code>babel-preset-typescript</code> to allow Babel to strip types similar to how <code>babel-preset-flow</code> works!
[...] you setup TS with <code>--no-emit</code> or use it in the editor/watch mode so that you can use preset-env and other Babel plugins.</p></div></div>
<img src="https://media.giphy.com/media/RrVzUOXldFe8M/giphy.gif" alt="yeah" style="width:200px;margin:20px auto;display:block">
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="programmation-orientée-objet">Programmation orientée Objet<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#programmation-orient%C3%A9e-objet" class="hash-link" aria-label="Lien direct vers Programmation orientée Objet" title="Lien direct vers Programmation orientée Objet">​</a></h3>
<p><em>Les concepts de la POO listés ci-après n'ont pas vocation à être présentés dans cet article. Si certains vous sont inconnus, découvrez-les dans la <a href="https://www.typescriptlang.org/docs/handbook/basic-types.html" target="_blank" rel="noopener noreferrer">documentation officielle</a></em></p>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="interface">Interface<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#interface" class="hash-link" aria-label="Lien direct vers Interface" title="Lien direct vers Interface">​</a></h4>
<p>Concept bien connu de la programmation orientée objet que l'on retrouve dans TypeScript. Les <a href="https://www.typescriptlang.org/docs/handbook/interfaces.html" target="_blank" rel="noopener noreferrer">interfaces</a> n'existent que dans le code TypeScript : il n'en reste rien dans la version transpilée en JavaScript. Cependant, elles ont de multiples avantages :</p>
<ul>
<li>Documenter le code en spécifiant la structure attendues des données passées en paramètres ou retournées par les fonctions.</li>
<li>Permettre la validation des déclarations de classes qui les implémentent (rôle de Contrat).</li>
<li>Étendre les interfaces de modules existants grâce à la <a href="https://www.typescriptlang.org/docs/handbook/declaration-merging.html" target="_blank" rel="noopener noreferrer">Combinaison de déclaration</a> ou <em>Declaration merging</em> (concept <strong>propre à TypeScript</strong> dont je recommande la lecture)</li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="class">Class<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#class" class="hash-link" aria-label="Lien direct vers Class" title="Lien direct vers Class">​</a></h4>
<p>L'arrivée d'ECMAScript 2015 a apporté le support des classes en JavaScript. Cependant, certaines notions de la POO sont manquantes. C'est le cas notamment :</p>
<ul>
<li>Des classes et méthodes <strong>abstraites</strong></li>
<li>Des attributs de visibilité (ou accessibilité) <code>private</code>, <code>protected</code>, <code>public</code></li>
</ul>
<p>Que l'<a href="https://www.typescriptlang.org/docs/handbook/classes.html" target="_blank" rel="noopener noreferrer">on retrouve</a> dans TypeScript.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="ok" src="https://vinceops.me/assets/images/oop_meme-273fe71555d9f841a27ff2a547786aa0.jpg" width="300" height="248" class="img_BhpN"></p></div>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="mais-aussi">Mais aussi...<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#mais-aussi" class="hash-link" aria-label="Lien direct vers Mais aussi..." title="Lien direct vers Mais aussi...">​</a></h4>
<p>Les <a href="https://www.typescriptlang.org/docs/handbook/enums.html" target="_blank" rel="noopener noreferrer">Énumérations</a> et les  <a href="https://www.typescriptlang.org/docs/handbook/generics.html" target="_blank" rel="noopener noreferrer">Génériques</a> (ou Types paramétrés / Templates). Bien que n'étant pas des concepts propres à la POO, ils existent dans la plupart des grands langages orientés object.</p>
<h5 class="anchor anchorWithStickyNavbar_FhrX" id="un-mot-sur-le-generic-programming">Un mot sur le <em>generic programming</em><a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#un-mot-sur-le-generic-programming" class="hash-link" aria-label="Lien direct vers un-mot-sur-le-generic-programming" title="Lien direct vers un-mot-sur-le-generic-programming">​</a></h5>
<p>Le support des Génériques (et TypeScript 2.8, avec ses types conditionnels) permet de définir des types avancés comme :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">StringProps</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">P</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">string</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">P</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">never</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">keyof</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>regroupant toutes les propriétés de type <code>string</code> de <code>T</code>.</p>
<p>Exemple d'utilisation :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> firstName</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> email</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> age</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> isMarried</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">serialize</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name constant" style="color:#36acaa">T</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">obj</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fields</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">Array</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">StringProps</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Ici, si l'on passe un objet <code>Person</code> (notre paramètre de type <code>T</code>) à la fonction <code>serialize</code>, le paramètre <code>fields</code> n'acceptera qu'un tableau de ses propriétés de type <code>string</code>.</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> mike </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Mike'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Smith'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">25</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ✓</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">serialize</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mike</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'firstName'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">serialize</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mike</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'firstName'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'email'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// error TS2345: Type '"firstname"' is not assignable to type '"firstName" | "email"'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">serialize</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mike</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'firstname'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// error TS2345: Type '"age"' is not assignable to type '"firstName" | "email"'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">serialize</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mike</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'firstName'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'age'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="support-de-jsx">Support de JSX<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#support-de-jsx" class="hash-link" aria-label="Lien direct vers Support de JSX" title="Lien direct vers Support de JSX">​</a></h3>
<p>TypeScript supporte <a href="https://reactjs.org/docs/introducing-jsx.html" target="_blank" rel="noopener noreferrer">JSX</a> intégralement (typage, analyse et transpilation). Pour l'exploiter, les fichiers contenant du JSX doivent avoir l'extension <code>.tsx</code> et l'option de compilation <code>jsx</code> (<code>tsconfig.json</code> &gt; <code>compilerOptions</code>) doit être activée. Trois valeurs sont disponibles pour cette dernière :</p>
<ul>
<li><code>preserve</code> : Le code JSX n'est pas transpilé et le fichier de sortie a pour extension <code>.jsx</code> - utile si vous souhaitez confier le traitement de JSX à un autre outil (Babel, par exemple)</li>
<li><code>react</code> : Le code JSX est transpilé vers du code React (<code>React.createElement</code>) et le fichier de sortie a pour extension <code>.js</code></li>
<li><code>react-native</code> : comme <code>preserve</code>, conserve le code JSX dans l'état, mais le fichier de sortie a pour extension <code>.js</code></li>
</ul>
<p>Prenons le composant React suivant, représentant une cellule cliquable sur un plateau de jeu :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Cell</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">props</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">player</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> PlayerEnum</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> baseClass </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'c4__cell'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> cellClasses </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">baseClass</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c"> </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation function" style="color:#d73a49">classNames</span><span class="token template-string interpolation punctuation" style="color:#393A34">(</span><span class="token template-string interpolation punctuation" style="color:#393A34">{</span><span class="token template-string interpolation"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string interpolation">    </span><span class="token template-string interpolation punctuation" style="color:#393A34">[</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation template-string interpolation">baseClass</span><span class="token template-string interpolation template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string interpolation template-string string" style="color:#e3116c">--empty</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation punctuation" style="color:#393A34">]</span><span class="token template-string interpolation operator" style="color:#393A34">:</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation punctuation" style="color:#393A34">(</span><span class="token template-string interpolation">props</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation">player </span><span class="token template-string interpolation operator" style="color:#393A34">===</span><span class="token template-string interpolation"> PlayerEnum</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation constant" style="color:#36acaa">NONE</span><span class="token template-string interpolation punctuation" style="color:#393A34">)</span><span class="token template-string interpolation punctuation" style="color:#393A34">,</span><span class="token template-string interpolation"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string interpolation">    </span><span class="token template-string interpolation punctuation" style="color:#393A34">[</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation template-string interpolation">baseClass</span><span class="token template-string interpolation template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string interpolation template-string string" style="color:#e3116c">--a</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation punctuation" style="color:#393A34">]</span><span class="token template-string interpolation operator" style="color:#393A34">:</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation punctuation" style="color:#393A34">(</span><span class="token template-string interpolation">props</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation">player </span><span class="token template-string interpolation operator" style="color:#393A34">===</span><span class="token template-string interpolation"> PlayerEnum</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation constant" style="color:#36acaa">A</span><span class="token template-string interpolation punctuation" style="color:#393A34">)</span><span class="token template-string interpolation punctuation" style="color:#393A34">,</span><span class="token template-string interpolation"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string interpolation">    </span><span class="token template-string interpolation punctuation" style="color:#393A34">[</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation template-string interpolation">baseClass</span><span class="token template-string interpolation template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string interpolation template-string string" style="color:#e3116c">--b</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation punctuation" style="color:#393A34">]</span><span class="token template-string interpolation operator" style="color:#393A34">:</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation punctuation" style="color:#393A34">(</span><span class="token template-string interpolation">props</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation">player </span><span class="token template-string interpolation operator" style="color:#393A34">===</span><span class="token template-string interpolation"> PlayerEnum</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation constant" style="color:#36acaa">B</span><span class="token template-string interpolation punctuation" style="color:#393A34">)</span><span class="token template-string interpolation punctuation" style="color:#393A34">,</span><span class="token template-string interpolation"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string interpolation">  </span><span class="token template-string interpolation punctuation" style="color:#393A34">}</span><span class="token template-string interpolation punctuation" style="color:#393A34">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">button className</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">cellClasses</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le composant <code>Cell</code> accepte une <code>prop</code> <code>player</code>, dont la valeur peut être <code>undefined</code> ou bien compatible avec l'énumération <code>PlayerEnum</code> :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">enum</span><span class="token plain"> PlayerEnum </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">NONE</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">A</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">B</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>La ligne suivante provoquera une erreur de compilation (un IDE compatible vous signalera l'erreur en amont) :</p>
<div class="language-jsx codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-jsx codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Cell</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">key</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript template-string template-punctuation string" style="color:#e3116c">`</span><span class="token tag script language-javascript template-string string" style="color:#e3116c">c-</span><span class="token tag script language-javascript template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token tag script language-javascript template-string interpolation" style="color:#00009f">x</span><span class="token tag script language-javascript template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token tag script language-javascript template-string string" style="color:#e3116c">-</span><span class="token tag script language-javascript template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token tag script language-javascript template-string interpolation" style="color:#00009f">y</span><span class="token tag script language-javascript template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token tag script language-javascript template-string template-punctuation string" style="color:#e3116c">`</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">player</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript string" style="color:#e3116c">'A'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<blockquote>
<p>Types of property 'player' are incompatible. Type 'string' is not assignable to type 'PlayerEnum | undefined'.</p>
</blockquote>
<p>Grâce à ce typage, VS Code sait nous dire quel type de propriété est attendue :</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="ts-jsx-intellisense-1" src="https://vinceops.me/assets/images/2018-03-18_20-16-05-5765afa0bedf2179ab827dc224d02e63.jpg" width="1006" height="139" class="img_BhpN"></p></div>
<p>Et bien évidemment, avec l'<em>autocompletion</em> :</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="ts-jsx-intellisense-2" src="https://vinceops.me/assets/images/2018-03-18_20-19-41-d24a68294ffec28b3d429b0a4bc99cf4.jpg" width="927" height="132" class="img_BhpN"></p></div>
<p>Le code JSX de notre composant <code>Cell</code> (<code>return &lt;button...</code>) est transpilé ainsi :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createElement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"button"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">className</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> cellClasses </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>On utilise <code>JSX.Element</code> pour typer des éléments JSX (par exemple, retournés par une fonction). Le namespace <code>JSX</code> est défini dans le package <code>@types/react</code>, qui contient (<strong>entre autres</strong>) la définition de tous les éléments HTML adaptée au JSX :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">IntrinsicElements</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// HTML</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  a</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">DetailedHTMLProps</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">AnchorHTMLAttributes</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">HTMLAnchorElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> HTMLAnchorElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  abbr</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">DetailedHTMLProps</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">HTMLAttributes</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">HTMLElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> HTMLElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  address</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">DetailedHTMLProps</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">HTMLAttributes</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">HTMLElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> HTMLElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  area</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">DetailedHTMLProps</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">AreaHTMLAttributes</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">HTMLAreaElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> HTMLAreaElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  article</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">DetailedHTMLProps</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">HTMLAttributes</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">HTMLElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> HTMLElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<hr>
<p><em>La liste n'est évidemment pas exhaustive et les arguments en faveur de TypeScript (pour le frontend, comme pour le backend) ne manquent pas.</em></p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="installation-et-migration">Installation et Migration<a href="https://vinceops.me/typescript-2-pourquoi-l-adopter#installation-et-migration" class="hash-link" aria-label="Lien direct vers Installation et Migration" title="Lien direct vers Installation et Migration">​</a></h2>
<p>À suivre dans la <a href="https://vinceops.me/typescript-3-installation-migration/">troisième partie</a> du dossier.</p>]]></content:encoded>
            <category>typescript</category>
        </item>
        <item>
            <title><![CDATA[TypeScript - 1/3 : Présentation]]></title>
            <link>https://vinceops.me/typescript-1-presentation</link>
            <guid>https://vinceops.me/typescript-1-presentation</guid>
            <pubDate>Sun, 22 Apr 2018 12:00:00 GMT</pubDate>
            <description><![CDATA[Première partie du dossier TypeScript]]></description>
            <content:encoded><![CDATA[<p><em>Première partie du dossier TypeScript</em></p>
<p>Le langage <a href="https://www.typescriptlang.org/" target="_blank" rel="noopener noreferrer">TypeScript</a> est l'une des technologies les plus appréciées de ces dernières années, dans le développement <em>Frontend</em> comme dans le <em>Backend</em>. <a href="https://insights.stackoverflow.com/survey/2017#technology" target="_blank" rel="noopener noreferrer">Sa popularité</a> ne cesse de <a href="https://slack.engineering/typescript-at-slack-a81307fa288d" target="_blank" rel="noopener noreferrer">croître</a> et il est au cœur de nombreux projets : <a href="https://github.com/angular/angular" target="_blank" rel="noopener noreferrer">Angular</a>, <a href="https://github.com/NativeScript/NativeScript" target="_blank" rel="noopener noreferrer">NativeScript</a>, <a href="https://github.com/ionic-team/ionic" target="_blank" rel="noopener noreferrer">Ionic</a>, <a href="https://github.com/microsoft/vscode" target="_blank" rel="noopener noreferrer">VS Code</a>, <a href="https://github.com/apollographql/apollo-server" target="_blank" rel="noopener noreferrer">Apollo GraphQL</a>, <a href="https://github.com/BabylonJS/Babylon.js" target="_blank" rel="noopener noreferrer">Babylon.js</a>, <a href="https://github.com/ReactiveX/rxjs" target="_blank" rel="noopener noreferrer">RxJS</a>, <a href="https://github.com/nestjs/nest" target="_blank" rel="noopener noreferrer">Nest</a>, <a href="https://github.com/typeorm/typeorm" target="_blank" rel="noopener noreferrer">TypeORM</a>, etc.</p>
<p>Il n'existe à l'heure actuelle aucune alternative, même si certaines technologies partagent des objectifs communs ou proposent des avantages similaires. C'est le cas de <a href="https://flow.org/" target="_blank" rel="noopener noreferrer">Flow</a>, le <em>type checker</em> développé par Facebook, ou (plus éloigné) du langage <a href="http://elm-lang.org/" target="_blank" rel="noopener noreferrer">elm</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="présentation">Présentation<a href="https://vinceops.me/typescript-1-presentation#pr%C3%A9sentation" class="hash-link" aria-label="Lien direct vers Présentation" title="Lien direct vers Présentation">​</a></h2>
<blockquote>
<p>"JavaScript that scales."</p>
</blockquote>
<p>TypeScript est un langage <a href="https://github.com/Microsoft/TypeScript" target="_blank" rel="noopener noreferrer">open source</a>, créé par Microsoft, transpilable en JavaScript. Pour l'anecdote, on retrouve <a href="https://en.wikipedia.org/wiki/Anders_Hejlsberg" target="_blank" rel="noopener noreferrer">Anders Hejlsberg</a>, créateur de C# (entre autres), derrière le projet.</p>
<p>Ses principaux objectifs sont :</p>
<ul>
<li>Le support des propositions existantes <em>et à venir</em> d'EcmaScript.</li>
<li>L'apport du typage <em>optionnel</em> à JavaScript.</li>
<li>L'identification anticipée <em>(static)</em> de codes potentiellement invalides.</li>
<li>La compilation vers du JavaScript optimisé, avec pour cible, au choix: ES3, ES5, ES6...</li>
</ul>
<p>Ce que TypeScript n'ambitionne pas de faire, entre <a href="https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals" target="_blank" rel="noopener noreferrer">autres</a> :</p>
<ul>
<li>Imiter les langages existants; mais plutôt exploiter la nature de JavaScript et les usages des développeurs comme guide pour rendre le langage pertinent</li>
<li>Utiliser un système de types "sage" (<em>sound</em>) :</li>
</ul>
<p>Le système de types de TypeScript n'est <strong>pas</strong> "sage", ce qui signifie qu'il autorise certaines opérations qui ne peuvent être vérifiées au moment de la compilation (plus d'informations <a href="https://www.typescriptlang.org/docs/handbook/type-compatibility.html" target="_blank" rel="noopener noreferrer">ici</a> : <em>"A Note on Soundness"</em>). C'est l'une des grandes différences majeures avec <a href="https://flow.org/" target="_blank" rel="noopener noreferrer">Flow</a>, comme expliquée par James Kyle <a href="https://discuss.reactjs.org/t/if-typescript-is-so-great-how-come-all-notable-reactjs-projects-use-babel/4887/2" target="_blank" rel="noopener noreferrer">sur le forum de React</a>.</p>
<p><em>Pour être en mesure d'exécuter les lignes de commande citées dans la suite de l'article, installez typescript :</em></p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">npm install -g typescript</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="superset-et-transpilation">"Superset" et Transpilation<a href="https://vinceops.me/typescript-1-presentation#superset-et-transpilation" class="hash-link" aria-label="Lien direct vers &quot;Superset&quot; et Transpilation" title="Lien direct vers &quot;Superset&quot; et Transpilation">​</a></h2>
<p>Entrons dans le vif du sujet : "TypeScript est un superset de JavaScript", c'est la <em>punchline</em> popularisée par Microsoft et partagée par de nombreux enthousiastes. Un superset apportant le typage, les interfaces, les énumérations, les types génériques, les décorateurs...
Si vous avez déjà lu des articles sur le langage, vous avez certainement aperçu un graphique similaire :</p>
<img src="https://vinceops.me/ts-circles.png" style="width:300px;height:300px" alt="typescript-superset">
<br>
<p>Il n'est pas totalement faux, mais à nuancer. En effet, avec l'option <code>allowJs</code>, Le compilateur TypeScript (<code>tsc</code>) accepte le code JavaScript en entrée et produit du code transpilé (selon les paramètres fournis) en sortie.</p>
<p>Un code passé en entrée :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// person.js</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">firstName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">firstName</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> firstName</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'John'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Person { firstName: 'John' }</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Sa compilation (ou plutôt, <em>transpilation</em>) :</p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">tsc --allowJs person.js --outDir dist</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le résultat ainsi transpilé, avec l'option <code>target</code> à <code>"es5"</code> (valeur par défaut) :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// dist/person.js</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> </span><span class="token maybe-class-name">Person</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/** </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@class</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">firstName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">firstName</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> firstName</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token maybe-class-name">Person</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'John'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Person { firstName: 'John' }</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Remarquez la lisibilité du code généré.</p>
<p>Par contre, si l'on renomme <code>person.js</code> (contenant notre code ES6) en <code>person.ts</code>, la compilation n'est plus possible :</p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">tsc person.ts</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<blockquote>
<p>person.ts(3,10): error TS2339: Property 'firstName' does not exist on type 'Person'.</p>
</blockquote>
<p>Le fait de passer ce fichier en tant que code TypeScript (et non JavaScript) à <code>tsc</code> fait échouer la transpilation. Le compilateur s'attend à analyser du code TypeScript valide. <strong>Ce code n'est pas du TypeScript valide, bien qu'il soit du JavaScript valide</strong>.
Par conséquent, la notion de "Superset" telle que vulgarisée par le graphique des 3 ensembles est imprécise : on ne peut  pas considérer ES6 comme un sous-ensemble de TypeScript.</p>
<p>Une syntaxe TypeScript valide, parmi d'autres :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// person.ts</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> firstName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'John'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Person { firstName: 'John' }</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>en utilisant <code>firstName</code> comme une <em>parameter property</em> (fonctionnalité de TypeScript <a href="https://vinceops.me/babel-plugin-param-props/">abordée et "babelisée"</a> sur ce blog). Sinon, il est nécessaire de déclarer <code>firstName</code> comme une <a href="https://babeljs.io/docs/plugins/transform-class-properties/" target="_blank" rel="noopener noreferrer">class property</a> et de l'affecter manuellement dans le constructeur.
La transpilation de ce code TypeScript produit le même code ES5 vu précédemment dans <code>dist/person.js</code>.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="pourquoi-ladopter">Pourquoi l'adopter<a href="https://vinceops.me/typescript-1-presentation#pourquoi-ladopter" class="hash-link" aria-label="Lien direct vers Pourquoi l'adopter" title="Lien direct vers Pourquoi l'adopter">​</a></h2>
<p>À suivre dans la <a href="https://vinceops.me/typescript-2-pourquoi-l-adopter">deuxième partie</a> du dossier.</p>]]></content:encoded>
            <category>typescript</category>
        </item>
        <item>
            <title><![CDATA[Créer un plugin Babel : Parameter Properties]]></title>
            <link>https://vinceops.me/babel-plugin-param-props</link>
            <guid>https://vinceops.me/babel-plugin-param-props</guid>
            <pubDate>Wed, 15 Nov 2017 00:00:00 GMT</pubDate>
            <description><![CDATA[Babel est un compilateur "source à source" (ou transpileur) les propriétés-paramètre (parameter properties).]]></description>
            <content:encoded><![CDATA[<p><a href="https://babeljs.io/" target="_blank" rel="noopener noreferrer">Babel</a> est un compilateur "source à source" (ou <em>transpileur</em>) : il analyse du code JavaScript, le transforme et en génère un nouveau. Les phases d'analyse et de transformation sont effectuées par des plugins (<em>plug-ins</em>) que l'on déclare dans la configuration de Babel.  La partie qui nous intéresse dans cet article concerne les plugins dits "customs", qui ne correspondent pas à une proposition d'évolution d'EcmaScript. Ici, j'ai décidé d'implémenter une fonctionnalité de TypeScript : les propriétés-paramètre (<em>parameter properties</em>).</p>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="contexte">Contexte<a href="https://vinceops.me/babel-plugin-param-props#contexte" class="hash-link" aria-label="Lien direct vers Contexte" title="Lien direct vers Contexte">​</a></h2>
<p>Les développeurs ayant eu le <em>grand</em> plaisir de réécrire leurs contrôleurs et services AngularJS <em>ES5-style</em> en <code>class</code> <em>ES6</em> ont probablement été frustrés par l'écriture d'une affectation en propriété de chaque dépendance injectée dans les constructeurs. C'est un problème que TypeScript gère très bien grâce aux "parameter properties" ou "propriétés-paramètre".</p>
<p><em>Dans les exemples qui suivent, on admet l'utilisation de <a href="https://github.com/olov/ng-annotate" target="_blank" rel="noopener noreferrer">ng-annotate</a>, afin de ne pas avoir à injecter "manuellement" les dépendances via la propriété <a href="https://docs.angularjs.org/guide/di#-inject-property-annotation" target="_blank" rel="noopener noreferrer">$inject</a>, ou directement dans la déclaration du service. Il existe d'ailleurs un <a href="https://github.com/schmod/babel-plugin-angularjs-annotate" target="_blank" rel="noopener noreferrer">plugin Babel pour ng-annotate</a>.</em></p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="es5">ES5<a href="https://vinceops.me/babel-plugin-param-props#es5" class="hash-link" aria-label="Lien direct vers ES5" title="Lien direct vers ES5">​</a></h3>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token string" style="color:#e3116c">'use strict'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">angular</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">module</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'MyAppModule'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">service</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'DragService'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token maybe-class-name">DragService</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">DragService</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter maybe-class-name">GestureListener</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">InterfaceManager</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">activate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">activate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'DragService instantiated'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Ce à quoi peut ressembler un service AngularJS écrit en ES5, si l'on suit les <a href="https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md" target="_blank" rel="noopener noreferrer">recommandations de John Papa</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="es6">ES6<a href="https://vinceops.me/babel-plugin-param-props#es6" class="hash-link" aria-label="Lien direct vers ES6" title="Lien direct vers ES6">​</a></h3>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">DragService</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter maybe-class-name">GestureListener</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">InterfaceManager</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access maybe-class-name">GestureListener</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">GestureListener</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access maybe-class-name">InterfaceManager</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">InterfaceManager</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'DragService instantiated'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">angular</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">module</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'MyAppModule'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">service</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'DragService'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token maybe-class-name">DragService</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Et sa transformation en <code>class</code>. Notez les affectations dans le constructeur :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access maybe-class-name">GestureListener</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">GestureListener</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access maybe-class-name">InterfaceManager</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">InterfaceManager</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>C'est de cette partie du code que l'on souhaite s'affranchir (surtout lorsque les dépendances sont nombreuses et qu'il est difficile d'y remédier sans réécrire une quantité importante de code).</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="typescript">TypeScript<a href="https://vinceops.me/babel-plugin-param-props#typescript" class="hash-link" aria-label="Lien direct vers TypeScript" title="Lien direct vers TypeScript">​</a></h3>
<p>Avec TypeScript, les <a href="https://www.typescriptlang.org/docs/handbook/classes.html" target="_blank" rel="noopener noreferrer">Parameter Properties</a> permettent d'automatiser ces affectations, en ajoutant un niveau d'accessibilité (<code>public</code>, <code>private</code>...) aux paramètres :</p>
<div class="language-typescript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-typescript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">DragService</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> GestureListener</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> InterfaceManager</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'DragService instantiated'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>L'accessibilité (<a href="https://github.com/tc39/proposal-private-fields" target="_blank" rel="noopener noreferrer">dont <code>private</code></a>) n'étant pas encore au programme des normalisations EcmaScript, comme les <em>parameter properties</em>, j'ai décidé de créer un (petit) plugin Babel permettant de générer automatiquement ces affectations :</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="es6--babel-plugin-proposal-parameter-properties">ES6 + <a href="https://github.com/VinceOPS/babel-plugin-proposal-parameter-properties" target="_blank" rel="noopener noreferrer">babel-plugin-proposal-parameter-properties</a><a href="https://vinceops.me/babel-plugin-param-props#es6--babel-plugin-proposal-parameter-properties" class="hash-link" aria-label="Lien direct vers es6--babel-plugin-proposal-parameter-properties" title="Lien direct vers es6--babel-plugin-proposal-parameter-properties">​</a></h3>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">@paramProperties</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">DragService</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">@pp </span><span class="token parameter maybe-class-name">GestureListener</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> @pp </span><span class="token parameter maybe-class-name">InterfaceManager</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'DragService instantiated'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">angular</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">module</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'MyAppModule'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">service</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'DragService'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token maybe-class-name">DragService</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Lors de l'étape de Transformation, le plugin génère les affectations des paramètres décorés par <code>@pp</code>, les insére dans le constructeur, puis supprime les décorateurs <code>@paramProperties</code> et <code>@pp</code>. Ce qui a pour effet de générer le même code que celui présenté plus haut (cf <strong>ES6</strong>).</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="fonctionnement-de-babel">Fonctionnement de Babel<a href="https://vinceops.me/babel-plugin-param-props#fonctionnement-de-babel" class="hash-link" aria-label="Lien direct vers Fonctionnement de Babel" title="Lien direct vers Fonctionnement de Babel">​</a></h2>
<div class="theme-admonition theme-admonition-info admonition_e5jt alert alert--info"><div class="admonitionHeading_W2ql"><span class="admonitionIcon_jWqd"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_VChT"><p>Pour des raisons de lisibilité/clarté, beaucoup de détails ont été laissés de côté, sur le fonctionnement de Babel et sur ses modules "clés". Pour un guide détaillé sur le transpileur et sur la création de plugin, référez-vous au <a href="https://github.com/thejameskyle/babel-handbook/blob/master/translations/en/plugin-handbook.md" target="_blank" rel="noopener noreferrer">babel-handbook</a>.</p></div></div>
<p>Babel analyse un code existant, le transforme puis le génère à nouveau. Pour ce faire, le transpileur construit un <a href="https://fr.wikipedia.org/wiki/Arbre_syntaxique_abstrait" target="_blank" rel="noopener noreferrer">AST</a> à partir du code <strong>analysé</strong>. Chaque nœud de l'AST est d'un type particulier, dont on retrouve la <a href="https://babeljs.io/docs/core-packages/babel-types" target="_blank" rel="noopener noreferrer">liste exhaustive</a> dans la documentation de Babel.  On peut générer l'AST d'un script à l'aide du <em>parser</em> de Babel, <a href="https://www.npmjs.com/package/babylon" target="_blank" rel="noopener noreferrer">babylon</a> :</p>
<div class="language-bash codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-bash codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">babylon script.js &gt; ast.json</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Il existe aussi AST Explorer, un outil en ligne qui permet d'accomplir le même travail en mode "playground". <a href="https://astexplorer.net/" target="_blank" rel="noopener noreferrer">https://astexplorer.net/</a></p>
<p>L'AST ainsi créé peut être <strong>transformé</strong> par Babel et par ses plugins.
Une fois la transformation terminée, Babel <strong>génère</strong> un nouveau code.</p>
<div style="text-align:center"><p><img decoding="async" loading="lazy" alt="Babel-chain" src="https://vinceops.me/assets/images/babel-chain-3-539e92755c1d1f2420ede0062d09a8bb.png" width="788" height="160" class="img_BhpN"></p></div>
<h2 class="anchor anchorWithStickyNavbar_FhrX" id="création-du-plugin">Création du plugin<a href="https://vinceops.me/babel-plugin-param-props#cr%C3%A9ation-du-plugin" class="hash-link" aria-label="Lien direct vers Création du plugin" title="Lien direct vers Création du plugin">​</a></h2>
<p>Conformément au <em>babel-handbook</em>, on démarre avec le squelette suivant :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter punctuation" style="color:#393A34">{</span><span class="token parameter"> </span><span class="token parameter literal-property property" style="color:#36acaa">types</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> t </span><span class="token parameter punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">visitor</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>C'est en réalité  <code>babel</code> qui est passé en paramètre de notre plugin, mais on n'utilisera que sa propriété <code>types</code>.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="la-traversée">La traversée<a href="https://vinceops.me/babel-plugin-param-props#la-travers%C3%A9e" class="hash-link" aria-label="Lien direct vers La traversée" title="Lien direct vers La traversée">​</a></h3>
<p>L'AST est traversé en utilisant le <em>pattern</em> <a href="https://fr.wikipedia.org/wiki/Visiteur_(patron_de_conception)" target="_blank" rel="noopener noreferrer">Visitor</a>. Pour chaque type de nœud que l'on souhaite traiter, il suffit d'ajouter une méthode correspondante. Dans notre cas, on va s'intéresser au type <code>ClassDeclaration</code>, puisque c'est sur les déclarations de <code>class</code> que porte notre décorateur <code>@paramProperties</code> :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token literal-property property" style="color:#36acaa">visitor</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function maybe-class-name" style="color:#d73a49">ClassDeclaration</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">path</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> state</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/* peut aussi s'écrire :</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    ClassDeclaration: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">        enter(path, state) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">            console.log(path.node);</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>En plus de la propriété <code>visitor</code>, les plugins peuvent aussi déclarer les fonctions <code>pre(state)</code> et <code>post(state)</code> qui permettent d'exécuter du code avant et après leur initialisation.
Notez que dans le cadre de cet article, l'objet <code>state</code> sera ignoré (inutilisé).</p>
<p>Notre plugin va effectuer les actions suivantes :</p>
<ul>
<li>Vérifier que la classe déclarée soit bien décorée avec <code>@paramProperties</code>.</li>
<li>Supprimer le décorateur (pour le retirer de l'AST, et donc du code généré par Babel).</li>
<li>Récupérer le nœud correspondant au constructeur de la classe.</li>
<li>Insérer dans le corps du constructeur une affectation pour chacun de ses paramètres décorés avec <code>@pp</code>. Les affectations doivent nécessairement être placées <em>après</em> l'appel éventuel de <code>super()</code>.</li>
</ul>
<p>Je recommande l'utilisation du <em>package</em> <a href="https://www.npmjs.com/package/@types/babel-types" target="_blank" rel="noopener noreferrer">@types/babel-types</a> qui permet une autocompletion exhaustive et très utile.</p>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="trouver-et-supprimer-le-décorateur">Trouver et supprimer le décorateur<a href="https://vinceops.me/babel-plugin-param-props#trouver-et-supprimer-le-d%C3%A9corateur" class="hash-link" aria-label="Lien direct vers Trouver et supprimer le décorateur" title="Lien direct vers Trouver et supprimer le décorateur">​</a></h3>
<p>Pour que Babel accepte d'<strong>analyser</strong> notre code décoré, il faut d'abord ajouter le plugin permettant au <em>parser</em> de "comprendre" les décorateurs : <a href="https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-decorators" target="_blank" rel="noopener noreferrer">babel-plugin-syntax-decorators</a>. Le plugin ajoute une propriété (array) <code>decorators</code> aux nœuds de l'AST.</p>
<p>On peut ensuite facilement récupérer notre décorateur, s'il existe :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DECORATOR</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'paramProperties'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * Look for the expected decorator and return it (if declared).</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> *</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@param</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">babel</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">types</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">ClassDeclaration</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment parameter" style="color:#999988;font-style:italic">node</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> ClassDeclaration node.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> *</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@return</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">babel</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">types</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">Decorator</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> The plugin-specific decorator (or `undefined`).</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">getDecorator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">node</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">decorators</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">find</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">decorator</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> decorator</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">expression</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DECORATOR</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><em>On se réfère à la <a href="https://babeljs.io/docs/core-packages/babel-types/#apidecorator" target="_blank" rel="noopener noreferrer">documentation</a> des types de Babel pour les propriétés de chaque type de nœud.</em></p>
<p>Si aucun décorateur n'est trouvé, le traitement de ce nœud est interrompu.
Sinon, on le supprime de notre noeud, pour qu'il n'apparaisse pas dans le code généré par Babel :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * Remove paramProperties decorators from the class</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * declaration.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> *</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@param</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">babel</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">types</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">ClassDeclaration</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment parameter" style="color:#999988;font-style:italic">node</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> Node decorated with 'paramProperties'.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">undecorate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    node</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">decorators</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">decorators</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">d</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> d</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">expression</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> d</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">expression</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DECORATOR</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="trouver-le-constructeur-et-le-modifier">Trouver le constructeur et le modifier<a href="https://vinceops.me/babel-plugin-param-props#trouver-le-constructeur-et-le-modifier" class="hash-link" aria-label="Lien direct vers Trouver le constructeur et le modifier" title="Lien direct vers Trouver le constructeur et le modifier">​</a></h3>
<p>Le constructeur peut être identifié grâce à son type <code>ClassMethod</code>. Il est en effet une méthode de la classe déclarée, et peut être trouvé dans son corps (propriété <code>body</code>), qui, conformément à la documentation, est de type <code>ClassBody</code>, et contient une propriété <code>body</code> qui est un tableau de <code>ClassMethod</code>. On a donc des nœuds de type <code>ClassMethod</code> dans <code>node.body.body</code>.</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * Get the constructor of the `node` class.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> *</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@param</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">babel</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">types</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">ClassDeclaration</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment parameter" style="color:#999988;font-style:italic">node</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> ClassDeclaration node.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> *</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@return</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">babel</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">types</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">ClassMethod</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> `node` class constructor.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">getConstructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> classBody </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> classBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">find</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">subNode</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">types</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">isClassMethod</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">subNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> subNode</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">kind</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'constructor'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><code>this.types</code> correspond au paramètre <code>types</code> passé dans le squelette de notre plugin.</p>
<p><em>Conformément à la documentation, la propriété <code>kind</code> d'un nœud <code>ClassMethod</code> est égale à 'get', 'set', 'method', ou '<strong>constructor</strong>'.</em></p>
<p>On peut ensuite modifier le corps du constructeur : y ajouter une affectation par paramètre. Si un appel à <code>super()</code> (il est forcément unique) est trouvé, alors on prend soin d'insérer les affectations <em>après</em> ce dernier (sinon, une exception sera levée).
<code>ClassMethod</code> possède une propriété <code>body</code> de type <code>BlockStatement</code> qui possède une propriété <code>body</code> étant un tableau de <code>Statement</code>. On tente donc de trouver dans <code>constructeur.body.body</code> un nœud <code>CallExpression</code> dont la fonction cible est de type <code>Super</code>.</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * Insert the parameter properties assignments in the constructor body.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * If a call to `super` is found, append the statements just after it,</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * otherwise, "prepend" the statements.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> *</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@param</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">babel</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">types</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">ClassMethod</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment parameter" style="color:#999988;font-style:italic">ctor</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> Class constructor.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">insertAssignments</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">ctor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> ctorBody </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> ctor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> superIndex </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> ctorBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">findIndex</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">n</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">types</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">isExpressionStatement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">types</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">isCallExpression</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">expression</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">types</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">isSuper</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">expression</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">callee</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> assignmentCount </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ctor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">params</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">param</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">isParamProperty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">param</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> assignment </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getAssignmentStatement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">param</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> index </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> superIndex </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> assignmentCount</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            ctorBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">splice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">index</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> assignment</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">assignmentCount</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">undecorateParameter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">param</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><em><code>isParameterProperty</code> filtre le tableau <code>decorators</code> du <code>param</code> à la recherche d'un décorateur <code>@pp</code>. Et <code>undecorateParameter</code> supprime <code>@pp</code> du tableau.</em></p>
<p>La méthode <a href="https://github.com/VinceOPS/babel-plugin-proposal-parameter-properties/blob/master/src/parameter-properties.js#L96" target="_blank" rel="noopener noreferrer"><code>getAssignmentStatement</code></a> permet de générer une affectation de type :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">param</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> param</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_FhrX" id="test-du-plugin">Test du plugin<a href="https://vinceops.me/babel-plugin-param-props#test-du-plugin" class="hash-link" aria-label="Lien direct vers Test du plugin" title="Lien direct vers Test du plugin">​</a></h3>
<p>J'ai testé (avec <a href="https://facebook.github.io/jest/" target="_blank" rel="noopener noreferrer">Jest</a>) deux axes du plugin : d'abord la génération de la transformation induite par le plugin, à l'aide des <em>snapshots</em> (gérés par Jest). Puis, plus dans le détail, les transformations faites dans l'AST.</p>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="snapshots">Snapshots<a href="https://vinceops.me/babel-plugin-param-props#snapshots" class="hash-link" aria-label="Lien direct vers Snapshots" title="Lien direct vers Snapshots">​</a></h4>
<p>Voici un exemple de test unitaire validant un <em>snapshot</em> :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> babel </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'babel-core'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> plugin </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'../'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword module" style="color:#00009f">default</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> syntaxDecorators </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'babel-plugin-syntax-decorators'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">describe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Decorated classes only: '</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">it</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'does transform when decorator is valid'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> example </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@paramProperties class DoCare { constructor(@pp prop1) {} }'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">code</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> babel</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">transform</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">example</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token literal-property property" style="color:#36acaa">plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">syntaxDecorators</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> plugin</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">expect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">code</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toMatchSnapshot</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le premier appel à <code>toMatchSnapshot</code> va créer un fichier dans un répertoire <code>__snapshots__</code>, contenant le code que Babel doit générer s'il utilise notre plugin:</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">exports</span><span class="token punctuation" style="color:#393A34">[</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">Decorated classes only:  does transform when decorator is valid 1</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">"class DoCare {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">  constructor(prop1) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    this.prop1 = prop1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">}"</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c"></span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>On assure ainsi l'échec du test en cas de modification du plugin ayant un impact sur le code de sortie, puisque les prochains appels à <code>toMatchSnapshot</code> ne correspondront plus au fichier généré. En cas d'évolution, le snapshot peut être mis à jour en exécutant <code>jest -u</code>.</p>
<h4 class="anchor anchorWithStickyNavbar_FhrX" id="transformations-de-last">Transformations de l'AST<a href="https://vinceops.me/babel-plugin-param-props#transformations-de-last" class="hash-link" aria-label="Lien direct vers Transformations de l'AST" title="Lien direct vers Transformations de l'AST">​</a></h4>
<p>Les tests se déroulent en deux temps : d'abord, on génère un morceau d'AST "manuellement" (que l'on pourrait aussi obtenir avec du code JavaScript (sous forme de string) passé à <strong>babylon</strong>). Ensuite, on s'assure du bon fonctionnement de nos transformations.</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// avant le test unitaire</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">CLASS_DECORATOR</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'paramProperties'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">PARAM_DECORATOR</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'pp'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> identifier </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">identifier</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'MyClass'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> decorator </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">decorator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">identifier</span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">CLASS_DECORATOR</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> classBody </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">classBody</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> classDeclaration </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">classDeclaration</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">identifier</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    classBody</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">decorator</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> paramDecorators </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">decorator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">identifier</span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">PARAM_DECORATOR</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Correspond à :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">@paramProperties</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyClass</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Puis vient le test :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">it</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'inserts the correct amount of assignments'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> paramsCount </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// constructor parameters names: prop0, prop1, prop2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> params </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">Array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">paramsCount</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">fill</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">e</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">prop</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">i</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> ctor </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">classMethod</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'constructor'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">identifier</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'constructor'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        params</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">e</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> identifier </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">identifier</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            identifier</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">decorators</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> paramDecorators</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> identifier</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// empty body: constructor(@pp prop0, @pp prop1, @pp prop2) {}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">blockStatement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> ctorBody </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> ctor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    classBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ctor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// [...]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Cette partie "complète" notre AST :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token plain">@paramProperties</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyClass</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">@pp prop0</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> @pp prop1</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> @pp prop2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Que l'on va pouvoir transformer puis tester :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">it</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'inserts the correct amount of assignments'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// [...]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    paramProps</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">insertAssignments</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ctor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">expect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ctorBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toBe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">paramsCount</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Ici, on s'assure que le nœud du constructeur ainsi transformé contiennent bien 3 <code>Statement</code> (contre 0 avant), conformément au résultat attendu :</p>
<div class="language-javascript codeBlockContainer_UdZb theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_VbSg"><pre tabindex="0" class="prism-code language-javascript codeBlock_OqWT thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_JAIc"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">prop0</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> prop1</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> prop2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prop0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> prop0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prop1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> prop1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prop2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> prop2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_kUYp"><button type="button" aria-label="Copier le code" title="Copier" class="clean-btn"><span class="copyButtonIcons_ybo1" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_H0E3"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_oztp"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Le code du plugin est disponible ici : <a href="https://github.com/VinceOPS/babel-plugin-proposal-parameter-properties" target="_blank" rel="noopener noreferrer">VinceOPS/babel-plugin-proposal-parameter-properties</a>.</p>]]></content:encoded>
            <category>babel</category>
            <category>typescript</category>
        </item>
    </channel>
</rss>