<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Maina Wycliffe</title>
    <description>The latest articles on DEV Community by Maina Wycliffe (@mainawycliffe).</description>
    <link>https://dev.to/mainawycliffe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F189151%2F30002a6a-0eef-4de4-82fb-41244031812f.jpg</url>
      <title>DEV Community: Maina Wycliffe</title>
      <link>https://dev.to/mainawycliffe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mainawycliffe"/>
    <language>en</language>
    <item>
      <title>On-Device AI with the Google Chrome Prompt API</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Mon, 17 Nov 2025 18:50:02 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/on-device-ai-with-the-google-chrome-prompt-api-2jbe</link>
      <guid>https://dev.to/playfulprogramming/on-device-ai-with-the-google-chrome-prompt-api-2jbe</guid>
      <description>&lt;p&gt;Unless you’ve been living under a rock, it’s hard to miss the rise of Generative AI. At the centre of this movement are &lt;strong&gt;Large Language Models (LLMs)&lt;/strong&gt; such as Google’s Gemini and OpenAI’s ChatGPT. Typically, building solutions around these models involves sending data to their APIs and receiving a response.&lt;/p&gt;

&lt;p&gt;But not everyone is comfortable with this approach. Concerns around &lt;strong&gt;privacy, trust, legal compliance, and governance&lt;/strong&gt; often arise. This is where &lt;strong&gt;on-device AI&lt;/strong&gt; comes in: data is processed locally, addressing most of these issues.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how to use the &lt;strong&gt;Chrome On-Device Prompt API&lt;/strong&gt; to process data locally. This is the first in a series of articles covering Chrome’s on-device AI capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Download Google Chrome &amp;amp; Enable Required Flags
&lt;/h3&gt;

&lt;p&gt;Make sure you’re running the latest version of Chrome (currently version 142). These APIs are Chrome-specific for now, though they may eventually become web standards.&lt;/p&gt;

&lt;p&gt;Enable the following flags by navigating to &lt;code&gt;chrome://flags&lt;/code&gt; in your browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;#prompt-api-for-gemini-nano&lt;/li&gt;
&lt;li&gt;#optimization-guide-on-device-model&lt;/li&gt;
&lt;li&gt;#prompt-api-for-gemini-nano-multimodal-input&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pv0ezj7v7tr4z4sj4oh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pv0ezj7v7tr4z4sj4oh.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, restart the browser, using the relaunch bar that will be displayed at the bottom of the page. You can learn more about Chrome Flags &lt;a href="https://developer.chrome.com/docs/web-platform/chrome-flags?ref=cms.mainawycliffe.dev" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can confirm that the api is enabled by running the following code inside the browser console, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;LanguageModel&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Model is enabled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Check Model Availability
&lt;/h3&gt;

&lt;p&gt;Now that we have enabled the on-device model on Chrome, we need to check if the user has already downloaded the model to use, and if not, download it. Otherwise, we can't prompt the model until that is done.&lt;/p&gt;

&lt;p&gt;We can do this by calling the &lt;code&gt;LanguageModel.availability()&lt;/code&gt; method, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;LanguageModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;availability&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above model checks whether the user has downloaded the model and is ready for use. If it's not, the next step is to download the model.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If not yet downloaded, you’ll need to trigger the download (~1.5 GB). Note that user interaction is required before downloading. You can check this with:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userActivation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create an instance of a built-in API&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another approach is to use a button to trigger the download, and then you wouldn't need to check for activation, as that would only be triggered when the user clicks the download button.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Download the Model
&lt;/h3&gt;

&lt;p&gt;Next, we can use the &lt;code&gt;LanguageModel.create&lt;/code&gt; method to trigger the download of the model and monitor the progress, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aiSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;LanguageModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;downloadprogress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;downloadProgress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to report the progress and inform the user of what's going on, as this is a large download and may take a while. For Angular, we can use signals in a service to report that back to the user, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChromeAiService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AILanguageModel&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;isAvailable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;availability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AIAvailability&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;downloadProgress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;isDownloading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;initializeSession&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAvailable&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Chrome AI is not available&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isDownloading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;downloadProgress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aiSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;LanguageModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;downloadprogress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;downloadProgress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aiSession&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isDownloading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;downloadProgress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isDownloading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Prompt the Model
&lt;/h3&gt;

&lt;p&gt;Once the model is downloaded, it's ready for use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;analyzeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR PROMPT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Please note, the model is very small, with a very limited number of tokens.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can also pass an initial prompt, which can be used to give it a persona and give it some ground rules, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;languageModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;LanguageModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;initialPrompts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You are a helpful assistant and you speak like a pirate.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can learn more about the Prompt API &lt;a href="https://developer.chrome.com/docs/ai/prompt-api?ref=cms.mainawycliffe.dev" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Clean up
&lt;/h3&gt;

&lt;p&gt;Afterwards, always terminate the session when you are done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We’ve covered enabling the Prompt API, checking availability, downloading the model, prompting it, and cleaning up. This is just one of several &lt;strong&gt;on‑device ML APIs&lt;/strong&gt; in Chrome — future articles will explore the rest.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Genkit Tool Calling: Give AI Models (LLMs) the Tools to Get Things Done</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Mon, 16 Jun 2025 13:27:38 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/genkit-tool-calling-give-ai-models-llms-the-tools-to-get-things-done-c4n</link>
      <guid>https://dev.to/playfulprogramming/genkit-tool-calling-give-ai-models-llms-the-tools-to-get-things-done-c4n</guid>
      <description>&lt;p&gt;AI Models are taking over the world, and we are all looking for ways to use them to solve different problems. One common issue with &lt;strong&gt;Large Language Models&lt;/strong&gt; (LLMs) is their training data, in that they only know what they were trained on. This is great when we want them to answer general questions, but not so useful when we want them to answer questions based on private data, i.e., customer data.&lt;/p&gt;

&lt;p&gt;There are a number of ways to solve this issue other than training your own AI models. One of the options is &lt;strong&gt;Retrieval-Augmented Generation&lt;/strong&gt; &lt;strong&gt;(RAG)&lt;/strong&gt;, where we ground the LLMs based on external data to improve the accuracy and relevance of the responses.&lt;/p&gt;

&lt;p&gt;The other option is &lt;strong&gt;Function Calling&lt;/strong&gt;, which is the subject of today’s article. &lt;strong&gt;Function calling&lt;/strong&gt;—known as &lt;strong&gt;tool calling&lt;/strong&gt; in Genkit—involves giving AI Models a structured way to interact with your application/system or external data sources (APIs) to accomplish various tasks and ensuring it has up-to-date data. The AI Model will then call those functions we provide to accomplish various tasks, such as to fetch user data, create a ticket for the user, and so on.&lt;/p&gt;

&lt;p&gt;To demonstrate this, we will be building a simple customer support agent that will answer questions from customers, and the AI Model will use the tools we provide to determine which tools it needs to call to accomplish the customer’s goal.&lt;/p&gt;

&lt;p&gt;If you are new to Genkit, please check out the official &lt;a href="https://genkit.dev/docs/get-started/" rel="noopener noreferrer"&gt;docs&lt;/a&gt; on how to get started, as this is beyond the scope of this post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please subscribe for future posts like this:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Subscribed&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Genkit Tools
&lt;/h2&gt;

&lt;p&gt;In Genkit, tools are special functions that contain information about what they are meant to accomplish and the means to accomplish the intended task — a function.&lt;/p&gt;

&lt;p&gt;A tool in Genkit is defined using the &lt;code&gt;defineTool&lt;/code&gt; method which accepts two arguments: a config object and a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toolName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tool Description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;customerId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// implementation to fetch customer details&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Please Note:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ai&lt;/code&gt; instance is created by calling genkit function, passing in a number of configurations such as plugins for the AI Model you want to use, and the default model. For more information, checkout the Genkit documentation, &lt;a href="https://genkit.dev/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;


&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;gemini20Flash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;googleAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@genkit-ai/googleai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;genkit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;genkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;genkit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;googleAI&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;gemini20Flash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Genkit tool calling support depends on the model, the model API, and the Genkit plugin for the model. Not all models support tool calling. Please consult the documentation to ensure that the model you intend to use supports Genkit tool calling.&lt;/p&gt;

&lt;p&gt;For this post, we will be using &lt;strong&gt;Gemini 2.0 Flash&lt;/strong&gt;, which supports tool calling.&lt;/p&gt;

&lt;p&gt;A config is where we describe what the tool does; we give a descriptive name and a description that describes the tool's intended purpose. We can also include input and output JSON schemas (supports &lt;a href="https://zod.dev/" rel="noopener noreferrer"&gt;zod&lt;/a&gt; out of the box) among other options. Only the description and name are required.&lt;/p&gt;

&lt;p&gt;The second argument is the function where we implement the tool’s objective. For instance, inside the function, we can make a DB call, an API call or any other deterministic operation, based on the tool’s intended objective.&lt;/p&gt;

&lt;p&gt;For instance, in our case, we might want to define a tool to fetch customer information, given a customer ID. In this case, we would define a &lt;code&gt;GetCustomerDetails&lt;/code&gt; tool that looks up the customer details from our database.&lt;/p&gt;

&lt;p&gt;Please note we are providing an input and output schema to ensure data is returned in a very specific format, all the time, and we will ensure we provide a good description of our tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCustomerDetailsTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GetCustomerDetails&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fetches details of a customer by ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The ID of the customer to fetch details for&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;outputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customerSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;customerId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This could be a database call or an API request in a real application.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Customer with ID &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; not found`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have created our first tool, we will need to pass it to the AI Model so it can use it, if need be, based on the customer’s question. In Genkit, there are several ways of achieving this, depending on whether we are using a flow, a prompt, or we are invoking the generate method directly inside the function.&lt;/p&gt;

&lt;p&gt;When calling the &lt;code&gt;generate&lt;/code&gt; method, passing the tool, in the tools’ options, alongside the prompt as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
  You are an eCommerce Customer Service AI.
  You can answer questions about customers and their orders.
  You have access to the following tools:
  - Get Customer Details: Fetches details of a customer by ID.
  - Get Customer Orders: Fetches orders for a specific customer, by customer ID.
  Use the tools to answer questions about customers and their orders.
  If you need to fetch customer details, use the Get Customer Details tool.
  If you need to fetch customer orders, use the Get Customer Orders tool.
  If you cannot answer a question, respond with "I don't know" or "I cannot answer that question".

  When answering questions, use the following format:
  - If the question is about customer details, provide the customer's name, email, and phone number.
  - If the question is about customer orders, provide the number of orders placed and details of the most recent order.
  - If the question is about a product, provide the product name, price, and description.

  Use all tools to fetch the necessary information, do not return IDs, instead return the relevant details the user is interested in.

  Example questions:
  - What is the email address of customer with ID 1?
  - How many orders has customer with ID 2 placed?

  The customer id is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;customerID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; and the question is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;getCustomerDetailsTool&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;toolChoice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;As you can see, our prompt is rather detailed, as we have to clearly instruct the AI Model to behave exactly the way we want, and reduce instances of it hallucinating. In cases where it has no answer, we want the AI model to say it doesn’t know, instead of hallucinating.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can put the above &lt;code&gt;generate&lt;/code&gt; method call in a function, and call it as shown below. On top of that, we are passing our tool — &lt;code&gt;getCustomerDetailsTool&lt;/code&gt; — in the tools section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
  &lt;span class="c1"&gt;// log our response&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, running the above can be very difficult, as you need to pass in the inputs in the correct format and almost impossible to debug. This is where &lt;strong&gt;Genkit Developer UI&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Genkit Developer UI
&lt;/h3&gt;

&lt;p&gt;Genkit provides a developer UI where you can view, invoke and test your flows, prompts, tools, among others, in a very user-friendly UI, which enhances the developer experience.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To launch the Genkit Developer UI, you can do so by running the following command:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;npx genkit start &lt;span class="nt"&gt;--&lt;/span&gt; npx tsx &lt;span class="nt"&gt;--watch&lt;/span&gt; index.ts
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In the above command, genkit is the genkit cli, and &lt;a href="https://tsx.is/getting-started" rel="noopener noreferrer"&gt;tsx&lt;/a&gt; is an NPM package for executing TypeScript files, without needing to transpile to Javascript first. &lt;code&gt;index.ts&lt;/code&gt; is the file which contains our code, and the entry file of our project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we have already defined our tool, running the above command, we should be able to see it in the UI and even interact with it, as shown below:&lt;/p&gt;

&lt;h4&gt;
  
  
  Defining a Genkit Flow
&lt;/h4&gt;

&lt;p&gt;For our case, we are going to switch to a flow. We will define a flow using the &lt;code&gt;defineFlow&lt;/code&gt; method, which takes two arguments — a config object and a function to be executed when the flow is called.&lt;/p&gt;

&lt;p&gt;For the flow config object, we will set the name of the flow, the input and output schema, keeping things simple for now. In the function, we will call the generate method, just like we previously did. We will return the text, so we can see the response of the AI Model in the UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assistant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eCommerceCustomerServiceAI&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;customerID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The ID of the customer to fetch details for&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The question or request for customer service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;outputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The response from the AI assistant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;customerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
      You are an eCommerce Customer Service AI.
      You can answer questions about customers and their orders.
      You have access to the following tools:
      - Get Customer Details: Fetches details of a customer by ID.
      - Get Customer Orders: Fetches orders for a specific customer, by customer ID.
      Use the tools to answer questions about customers and their orders.
      If you need to fetch customer details, use the Get Customer Details tool.
      If you need to fetch customer orders, use the Get Customer Orders tool.
      If you cannot answer a question, respond with "I don't know" or "I cannot answer that question".

      When answering questions, use the following format:
      - If the question is about customer details, provide the customer's name, email, and phone number.
      - If the question is about customer orders, provide the number of orders placed and details of the most recent order.
      - If the question is about a product, provide the product name, price, and description.

      Use all tools to fetch the necessary information, do not return IDs, instead return the relevant details the user is interested in.

      Example questions:
      - What is the email address of customer with ID 1?
      - How many orders has customer with ID 2 placed?

      The customer id is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;customerID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; and the question is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
      `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;getCustomerDetailsTool&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;toolChoice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our input schema will accept a customer ID and a question from the customer. The customer ID would likely come from the user session, while the question would be what the prompt the user entered in the chat input or system-generated, doesn't matter that much for this article.&lt;/p&gt;

&lt;p&gt;Next, we can use the developer UI to test the flow and see if we can get some user details from our database (I know it’s fake).&lt;/p&gt;

&lt;p&gt;You may be wondering, how do we know it’s working? The developer UI provides a stack trace to show you what exactly when during the execution, as shown below:&lt;/p&gt;

&lt;p&gt;As you can see, this can be very helpful when troubleshooting your Genkit application and trying to figure out where things are going wrong. It will show you all the calls it made to the tools, including the inputs and outputs of each step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finalising the Agent
&lt;/h3&gt;

&lt;p&gt;As it currently stands, no customer will be asking about their names, but hopefully, you get the idea. The customer would likely want to know the status of their orders, among other things. We will add more tools for getting order information and product information, following the template we have seen earlier, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCustomerOrdersTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GetCustomerOrders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fetches orders for a specific customer, by customer ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The ID of the customer to fetch orders for&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;outputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderSchema&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;customerId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customerId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProductDetailsTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GetProductDetails&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fetches product details by product ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The ID of the product to fetch details for&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;outputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;productSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;productId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Product with ID &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; not found`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, we will add the above tools to the tools section, in the generate method, next to the one we already have, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assistant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... nothing changes here&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;customerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`...`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;getCustomerDetailsTool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="c1"&gt;// we add the tools here&lt;/span&gt;
        &lt;span class="nx"&gt;getCustomerOrdersTool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nx"&gt;getProductDetailsTool&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, we can use the Genkit Developer UI to test whether our flow and tools work.&lt;/p&gt;

&lt;p&gt;As you can see, the AI model — in our case, Gemini — figures out the status of the customers’ orders and associates them with products by utilising the different tools we provided. While the prompt can be improved to allow the customer not to be very specific, and still accomplish the same goals, hopefully, you get the idea of how we can give LLMs the ability to interact with our systems to accomplish different goals.&lt;/p&gt;

&lt;p&gt;If you are interested, you can find the above source code &lt;a href="https://github.com/mainawycliffe/genkit-tool-calling" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclussion
&lt;/h2&gt;

&lt;p&gt;In this post, we discussed &lt;strong&gt;function calling&lt;/strong&gt; that allows you to give AI models access to your applications and system, so that they can get things done. We also looked at the Genkit Developer UI, for the purpose of testing and debugging our flows, tools and applications we are building on top of AI models.&lt;/p&gt;

&lt;p&gt;I hope this article gave you ideas on how you can use Genkit to build AI agents to help accomplish various tasks on behalf of customers, and if you have any questions, please feel free to put them in the comment section below.&lt;/p&gt;

&lt;p&gt;Until next time, keep on learning.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Ready to Move From AI Hype to Real-World Results?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At Unstacked Labs, we specialise in building practical AI agents, like the one in this article, that automate complex workflows and solve real business problems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://unstacked.dev/" rel="noopener noreferrer"&gt;Let's discuss your company needs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tutorial</category>
      <category>javascript</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Level Up Your Testing Game with Jest Spies and Asymmetric Matchers</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Mon, 05 May 2025 15:27:19 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/level-up-your-testing-game-with-jest-spies-and-asymmetric-matchers-dj6</link>
      <guid>https://dev.to/playfulprogramming/level-up-your-testing-game-with-jest-spies-and-asymmetric-matchers-dj6</guid>
      <description>&lt;p&gt;Over my long career as a software engineer, unit testing involving third-party APIS, such as database calls, etc., has always proven challenging. And let’s be honest, it’s pretty rare to write an application where all functions are pure, i.e., self-contained, and don’t interact with third-party APIS—a topic I would really like to explore at some point in the future. For more on this and other topics, stay subscribed.&lt;/p&gt;

&lt;p&gt;Let’s take the following simple function that gets items from the database - Dynamodb. Using the AWS SDK (v3), this function would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;docClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DynamoDBDocumentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getToDo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;docClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GetCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Avoid assertions, whenever possible&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ExchangeRateDBObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above function will use the AWS SDK to call the Dynamodb API and retrieve a to-do item with a given ID from the database. As long as you don’t have permission issues, it works.&lt;/p&gt;

&lt;p&gt;On the other hand, writing unit tests for it might be tricky, as the test would require access to an actual AWS Account or a local version of Dynamodb, each with its own set of challenges.&lt;/p&gt;

&lt;p&gt;There are several ways to handle this, which I won’t go into in this article, but one of my favourites is mocking the Dynamodb SDK (Or any other SDK). The problem I generally find with mocks is that developers do not check whether the mocked function was called correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F937kazmzdl62ewamv053.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F937kazmzdl62ewamv053.gif" width="260" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Jest Spies
&lt;/h3&gt;

&lt;p&gt;To give you an example, when we mock out our Document Client above, we not only need to respond with the correct return signature—for instance, in our case, we only care about the Item property—but we also need to ensure that we passed in the correct information to the client.&lt;/p&gt;

&lt;p&gt;In our case, the table name and the key must be correct; otherwise, if incorrect, our function would not work in the real world.&lt;/p&gt;

&lt;p&gt;This is where Jest Spies come in. &lt;strong&gt;The Jest spy method allows us to monitor the behaviour of other functions without changing the underlying code for the purpose of testing&lt;/strong&gt;. With spies, we can observe a few things, such as the times it was called and the parameters or inputs it was called with.&lt;/p&gt;

&lt;p&gt;So, for instance, to test the above function, we would need to spy on &lt;code&gt;docClient&lt;/code&gt; send method, returning the necessary response for our function to use, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Should pass the correct Key to the DB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spyOnDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;docClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;send&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mockToDo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getToDo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we run the above test, it will succeed using the mock test, as shown below.&lt;/p&gt;

&lt;p&gt;But if you recall correctly, we have mocked (using the &lt;code&gt;jest.spyOn&lt;/code&gt; method) out our SDK call, but we aren’t doing anything to verify that we are calling our SDK correctly, which was one of my gripes with mocks in the first place.&lt;/p&gt;

&lt;p&gt;We can now use a number of methods from the Jest matchers, such as &lt;code&gt;toHaveBeenCalled&lt;/code&gt; and &lt;code&gt;toHaveBeenCalledWith&lt;/code&gt; to ensure that our SDK/ function we are spying on was called a number of times, once in our case and was with the correct inputs/parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spyOnDB&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above matcher checks that our SDK was called; it doesn’t check whether it was called once or twice. If we wanted to be specific, Jest provides a different matcher that you can use to ensure the number of calls - &lt;code&gt;toHaveBeenCalledTimes&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spyOnDB&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledTimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If our SDK is called more than once or not called at all, the test will fail. Neat, right?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27yedhjgnpabpzsdogfq.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27yedhjgnpabpzsdogfq.jpeg" width="633" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we can check whether the SDK passed the correct parameters. For that, we will use the &lt;code&gt;toHaveBeenCalledWith&lt;/code&gt; method to check whether the correct inputs were passed to our AWS SDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spyOnDB&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, while we care about the above input, the GetCommand class transforms our input and appends some metadata, which we don’t care about for our test, but is still important. Due to that, the above test will fail.&lt;/p&gt;

&lt;p&gt;As seen above, our SDK input contains much more information than what we are checking, with the information we need nested somewhere in there. This is where Jest comes to the rescue with another feature—asymmetric Matchers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asymmetric Matchers in Jest
&lt;/h3&gt;

&lt;p&gt;Asymmetric Matchers are magical in Jest, &lt;strong&gt;as they allow us flexibility when matching and asserting results in Jest&lt;/strong&gt;, such as partial matching, as we want.&lt;/p&gt;

&lt;p&gt;For instance, let’s say we have a random ID generator that’s prefixed, e.g., &lt;code&gt;user_UUID_STRING&lt;/code&gt;. We could mock out the ID generator function to return a predetermined string—deterministic behaviour is important for testing. Another option is to use asymmetric matchers to check whether the returned ID contains our prefix, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;USER_DETAILS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Ensure the id is a string and starts with "user_"&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringContaining&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;// Or ensure the date is in the correct format&lt;/span&gt;
    &lt;span class="na"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringMatching&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\d{4}&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;\d{2}&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;\d{2}&lt;/span&gt;&lt;span class="sr"&gt;T&lt;/span&gt;&lt;span class="se"&gt;\d{2}&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\d{2}&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\d{2}&lt;/span&gt;&lt;span class="sr"&gt;.&lt;/span&gt;&lt;span class="se"&gt;\d{3}&lt;/span&gt;&lt;span class="sr"&gt;Z$/&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we are ensuring that the ID starts with the user_ prefix and the updatedAt date is of the correct matchers.&lt;/p&gt;

&lt;p&gt;Circling back to our previous example, we now know that we need to ensure that the object passed to our SDK spy contains the following object, as we don’t care about the metadata and other details that the GetCommand appends.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jest provides an asymmetric matcher for just this situation - &lt;code&gt;expect.objectContaining&lt;/code&gt;. And this will check the results to see whether it contains the object we pass in, instead of strictly checking it, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spyOnDB&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectContaining&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectContaining&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In layman’s terms, we are doing a partial check, and as long as the fields that we specify exist within the results, our test will parse, as shown below:&lt;/p&gt;

&lt;p&gt;On top of that, Jest provides a good number of asymmetric matchers that you can use to make your life a little bit easier.&lt;/p&gt;

&lt;p&gt;Just keep in mind that you need to ensure you are testing the most critical aspect of your code, and don’t use this as a shortcut by overusing matchers such as &lt;code&gt;expect.anything&lt;/code&gt; or &lt;code&gt;expect.any&lt;/code&gt;, which can literally match any string.&lt;/p&gt;

&lt;p&gt;You can learn more about Asymmetric Matchers &lt;a href="https://jestjs.io/docs/expect#asymmetric-matchers" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, unit testing when dealing with third-party APIS can be challenging, especially when it comes to ensuring that mocks accurately reflect the interactions with the real SDKS.&lt;/p&gt;

&lt;p&gt;By leveraging both Jest Spies and Asymmetric Matchers, developers can create more robust, reliable and more effective tests that not only verify the functionality of their own functions but also confirm that the SDKS are being called correctly with the right parameters.&lt;/p&gt;

&lt;p&gt;This enhances the reliability of your tests and helps maintain the integrity of your application's behaviour. Remember, while mocking provides a useful abstraction layer, focusing on meaningful assertions that capture the critical aspects of your application when using asymmetric matchers is essential, making sure that critical elements are what they should be while ignoring everything else.&lt;/p&gt;

&lt;p&gt;By doing so, you'll be well-equipped to navigate the complexities of unit testing in a world full of dependencies. Happy testing!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Exploring Routes Rendering Modes in Angular</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Mon, 10 Feb 2025 09:37:27 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/exploring-routes-rendering-modes-in-angular-bjg</link>
      <guid>https://dev.to/playfulprogramming-angular/exploring-routes-rendering-modes-in-angular-bjg</guid>
      <description>&lt;p&gt;Over the last few years, Angular has grown through some significant and important changes. One of those changes was incorporating server-side rendering into Angular instead of a library like it used to be with Angular Universal, the predecessor of Angular SSR (&lt;code&gt;@angular/ssr&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now, every angular application, out of the box, by default, uses SSR, which is an opt-out feature. For most people, when building Angular apps, it either needs to be server-side rendered or not; for instance, a dashboard behind a login wall doesn’t need SSR, while an e-commerce site needs it.&lt;/p&gt;

&lt;p&gt;However, there are applications where there are some pages that are behind a login wall, and some public routes. If we circle back to our e-commerce site example, checkout pages, order pages, etc., are such examples that are probably behind a login wall, while product pages are public.&lt;/p&gt;

&lt;p&gt;If you enable SSR on such a route behind a login wall, and someone visits the page, Angular will render the login page (or wherever the Auth Guards redirect them). When the page is loaded, Angular will determine the user is logged in and redirect them back to the actual page, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6qzt44i5bxbq17hvys5v.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6qzt44i5bxbq17hvys5v.gif" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means the user will see a flash on the login page before seeing the actual page. This happens because, in our case, the authentication context is only available on the browser, not the server, and hence, on the server, the user is not logged in, but on the browser, the user is.&lt;/p&gt;

&lt;p&gt;If you encountered this, like I did, before Angular 19, you would have to disable SSR, as that’s not an optimal user experience. However, the Angular team introduced in Angular 19 the concept of render modes for individual routes, or what is called hybrid rendering.&lt;/p&gt;

&lt;p&gt;Instead of all routes either being client-side rendered (CSRd) or server-side rendered (SSRd), you can now choose what to do for each route. On top of that, they also added the ability to perform static site generation (SSG) for individual routes.&lt;/p&gt;

&lt;p&gt;Let’s see some code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Server Routes Manually
&lt;/h2&gt;

&lt;p&gt;Please note that this feature is in &lt;a href="https://angular.dev/reference/releases#developer-preview" rel="noopener noreferrer"&gt;developer preview&lt;/a&gt;, so use it cautiously. For more information on what this means, please check out the following link on Angular versioning &lt;a href="https://angular.dev/reference/releases" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before we can go any further, ensure you are on Angular 19. Angular has introduced a concept for Server Routes in which you can declare what to do for certain routes. To take the example above, we have two routes, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    canActivate: [redirectIfNotLoggedInGuard],
  },
  {
    path: 'login',
    component: LoginComponent,
    canActivate: [redirectIfLoggedInGuard],
  },
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the above route configuration, we can add server route configurations using the path and the render mode we need. I chose to store them next to each other, but it can also live in its server routes file - whatever floats your boat.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
import { RenderMode, ServerRoute } from '@angular/ssr';

...

export const serverRoutes: ServerRoute[] = [
  {
    path: '',
    renderMode: RenderMode.Client,
  },
  {
    path: 'login',
    renderMode: RenderMode.Server,
  },
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The render mode accepts one of three values, &lt;code&gt;RenderMode.Client&lt;/code&gt;, &lt;code&gt;RenderMode.Server&lt;/code&gt;, and &lt;code&gt;RenderMode.Prerender&lt;/code&gt;. For our very simple example above, we are &lt;code&gt;RenderMode.Client&lt;/code&gt; for the home page, so it will not be server-side rendered, and then &lt;code&gt;RenderMode.Server&lt;/code&gt; for the login page, it will be server-side rendered.&lt;/p&gt;

&lt;p&gt;Please note, for now, you have to add all routes to the Server Routes.&lt;/p&gt;

&lt;p&gt;Once we set up our routes, we finally need to provide the server routes in our app config so that Angular can use them. We achieve this by using the &lt;code&gt;provideServerRouting&lt;/code&gt; function and passing in the server routes we configured.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
import { provideServerRendering } from '@angular/platform-server';
import { provideServerRouting } from '@angular/ssr';
...

export const appConfig: ApplicationConfig = {
  providers: [
    ...
    provideServerRouting(serverRoutes),
    provideRouter(routes),
    ...
  ],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it. If we circle back to our example, you can see that the login page flash is completely gone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdzvbv2cup3841qvgdnmb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdzvbv2cup3841qvgdnmb.gif" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the code for the above application &lt;a href="https://github.com/unstacked-labs/angular-router-render-modes-demo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up For New Projects
&lt;/h3&gt;

&lt;p&gt;Of course, this is Angular we are talking about. With the magic of schematics, you can automate the above process; you will only have to configure your routes.&lt;/p&gt;

&lt;p&gt;If you are starting a new project, Angular provides a flag &lt;code&gt;--server-routing&lt;/code&gt; that enables this for the new project when setting it up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng add @angular/ssr --server-routing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this brief article, we looked at Rendering Modes in Angular and how we can use them to provide a better user experience for our users. Before this, your options were limited; you could either use SSR or not use SSR if it broke the UX of your users. But with render modes, you can enable SSR where it makes sense, Prerender pages that make sense and CSR pages that make sense, ensuring a much better user experience for our users.&lt;/p&gt;

&lt;p&gt;That’s it from me, and until next time, happy coding.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Why do we have const enums in Typescript?</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Mon, 17 Jun 2024 13:33:22 +0000</pubDate>
      <link>https://dev.to/allthingstypescript/why-do-we-have-const-enums-in-typescript-4l0</link>
      <guid>https://dev.to/allthingstypescript/why-do-we-have-const-enums-in-typescript-4l0</guid>
      <description>&lt;p&gt;Typescript usually has two schools of thought—enums and unions—with strong supporters on both sides of the argument. In today's issue, I want to avoid that debate and focus solely on Enums, specifically a different, lesser-known version of enums: const enums.&lt;/p&gt;

&lt;p&gt;Before we go any further, let’s briefly talk about what enums are: Enums allow developers to define a list of named constants representing distinct states within their application. For instance, if you wanted to have a switch button, the values can either be on or off, and an enum is perfect to represent this state, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjh28zrheabvrj4uqcxvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjh28zrheabvrj4uqcxvw.png" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you can use the above enum, just like any type in Typescript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiqkfe5i4ilz77smyfms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiqkfe5i4ilz77smyfms.png" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To understand the difference between enums and const enums, we first need to understand their behavior after compilation before the behavior is very similar.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you want to learn Typescript with weekly lessons, please subscribe to my &lt;a href="https://www.allthingstypescript.dev/" rel="noopener noreferrer"&gt;newsletter&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;In the book &lt;a href="https://effectivetypescript.com/" rel="noopener noreferrer"&gt;Effective Typescript by Don Vanderkom&lt;/a&gt; (a strongly recommended read), the author says that typescript has no impact on Javascript runtime. This is because Types are removed during transpilation, leaving you with good old Javascript. You can learn more about this relationship in this &lt;a href="https://www.allthingstypescript.dev/p/typescript-and-javascript-two-sides" rel="noopener noreferrer"&gt;issue&lt;/a&gt;, which we covered a few weeks ago.&lt;/p&gt;

&lt;p&gt;Enums are one of the few features TypeScript has which is not a type-level extension of JavaScript—&lt;a href="https://www.typescriptlang.org/docs/handbook/enums.html" rel="noopener noreferrer"&gt;Official TS Docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Of course, this isn’t always the case, and Enums are one of those exceptions, with Enums getting converted into objects instead of being removed, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fods6q0n1i6nlnvsbde7p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fods6q0n1i6nlnvsbde7p.png" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, when we pass an enum, the object that is produced during the transpilation process is referenced, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfi31i0v6s61l1ga7uw1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfi31i0v6s61l1ga7uw1.png" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another thing to note about enums is that the values of each element in an Enum are numbers - &lt;em&gt;incrementing from 0, from the top down, unless the first number is indicated&lt;/em&gt; - instead of the values we entered above, so in our case, &lt;code&gt;ON&lt;/code&gt; would be &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;Off&lt;/code&gt; would be &lt;code&gt;1&lt;/code&gt;. Below is a case where the initial number is indicated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafotjmv4sx95pjxkhcit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafotjmv4sx95pjxkhcit.png" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, On is &lt;code&gt;100&lt;/code&gt; and Off is &lt;code&gt;101&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This isn’t always the desired behavior, but it can be fixed by explicitly adding the value of each element in the enum, such as having the value be a string.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fal95ddemhziuroavwrdy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fal95ddemhziuroavwrdy.png" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;String Enums&lt;/p&gt;

&lt;p&gt;Or even an expression, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2p9ad3u002sf5aggan0h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2p9ad3u002sf5aggan0h.png" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Computed Enums&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you like my content and want to support my work, please consider supporting me (&lt;/strong&gt;&lt;em&gt;&lt;strong&gt;you can buy me a double latte, the juice that powers my creativity and determination ☕️&lt;/strong&gt;&lt;/em&gt;&lt;strong&gt;) through &lt;a href="https://github.com/sponsors/mainawycliffe/" rel="noopener noreferrer"&gt;Github Sponsors&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/sponsors/mainawycliffe/" rel="noopener noreferrer"&gt;☕️ Consider buying me a cup of coffee&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Const Enums
&lt;/h3&gt;

&lt;p&gt;This isn’t always desired, and that's where const enums come in. They are just like regular enums, but they are prefixed by the const keyword before their declaration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3yybucis49ywhyrc772c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3yybucis49ywhyrc772c.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The other important difference is that const enum values get inlined instead of producing an object, taking us back to zero impact on the JS runtime, as const enums do not generate objects after transpilation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4at683zyn76p1oszedn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4at683zyn76p1oszedn.png" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generally speaking, regular enums are valid solutions, but in those cases where you don’t want to pay the penalty of extra code generated by using regular enums, const enums are a very good solution, as they don’t generate any code for their support.&lt;/p&gt;

&lt;p&gt;As you can see, no more &lt;code&gt;Switch&lt;/code&gt; object is being created. Of course, just like with regular enums, we still have the same issue of enum element values being incremental numbers unless otherwise specified.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5pn2s6wg2zw7u5r5e2z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5pn2s6wg2zw7u5r5e2z.png" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this issue, we examined the difference between enums and const enums. Unlike regular enums, const enums don’t generate the javascript object; the code is inlined. This means that you are not paying the penalty for extra code generation that you get when using regular enums.&lt;/p&gt;

&lt;p&gt;While this is normally not a concern for most projects, in some cases, it can have a negative impact, leading to large JS code being produced and longer build / transpilation times. This can easily be solved by using const enums, which would be easier to refactor compared to alternative solutions such as unions.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Making Generics Types Optional - Generics Fundamentals in Typescript</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Tue, 30 Apr 2024 16:20:31 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/making-generics-types-optional-generics-fundamentals-in-typescript-1m11</link>
      <guid>https://dev.to/playfulprogramming/making-generics-types-optional-generics-fundamentals-in-typescript-1m11</guid>
      <description>&lt;p&gt;In the last two issues, we started exploring generics, where we looked at the &lt;a href="https://www.allthingstypescript.dev/p/generic-constraints-a-gentle-introduction" rel="noopener noreferrer"&gt;fundamentals of generics&lt;/a&gt; and how to &lt;a href="https://www.allthingstypescript.dev/p/generic-constraints-a-gentle-introduction" rel="noopener noreferrer"&gt;create generics constraints&lt;/a&gt;. I believe this has given you a good foundation for working with generics in Typescript.&lt;/p&gt;

&lt;p&gt;In this issue, I wanted to explore how we can make a generic Type optional by providing a default for the Type variable, that can be used when no Type is passed in and Typescript cannot infer the Type. Before we can look at generics, let’s draw some parallels with functions and how defaults work values for functional arguments.&lt;/p&gt;

&lt;p&gt;Let’s take the following simple example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function doSomething(input: string) {
    // do something
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, the function &lt;code&gt;input&lt;/code&gt; parameter is required. In some cases, we want to provide a fallback value, that will be used if the function is called without a value.&lt;/p&gt;

&lt;p&gt;For functions, the syntax to achieve this is the one shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjmlbkz34vpoz013atfkj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjmlbkz34vpoz013atfkj.png" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above example, we are simply telling Javascript that if the &lt;code&gt;input&lt;/code&gt; parameter isn’t provided or undefined, use &lt;code&gt;default-value&lt;/code&gt; as the value for the variable. This makes the input string optional, and not required.&lt;/p&gt;

&lt;p&gt;While Typescript will type-check the function’s &lt;code&gt;input&lt;/code&gt; parameter if provided an incorrect Type or if we simply don’t provide it, it also means that we need to provide the input every time we call the function.&lt;/p&gt;

&lt;p&gt;By providing a default value, we made the parameter optional, but this also means we have also expanded the types from being just string to string and undefined and to consume it, we might need to narrow the type. You can learn more about type narrowing &lt;a href="https://www.allthingstypescript.dev/p/narrowing-types-in-typescript" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, by providing a default value, it means we don’t need to provide it, so we don’t have to do the extra step of checking if the input is string or undefined, avoiding the extra step for narrowing types, as we already have a fallback value, when undefined.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you like my content and want to support my work, please consider supporting me (&lt;/strong&gt;&lt;em&gt;&lt;strong&gt;you can buy me a double latte, the juice that powers my creativity and determination ☕️&lt;/strong&gt;&lt;/em&gt;&lt;strong&gt;) through &lt;a href="https://github.com/sponsors/mainawycliffe/" rel="noopener noreferrer"&gt;Github Sponsors&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/sponsors/mainawycliffe/" rel="noopener noreferrer"&gt;☕️ Consider buying me a cup of coffee&lt;/a&gt;&lt;/p&gt;




&lt;h4&gt;
  
  
  What does this have to do with generics?
&lt;/h4&gt;

&lt;p&gt;Default Types for generics types work similarly. We can achieve the same thing we did with function parameters with Generics, where we can provide a fallback type for the &lt;strong&gt;type variable&lt;/strong&gt; if not provided and cannot be inferred.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A type variable&lt;/strong&gt; is a special kind of variable that works on types rather than values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s look at an example. Let’s create a simple utility type. Utility types utilize generics to help you do type transformation. Typescript has some in-built utility types that you can learn more about &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our utility type will take two types (&lt;em&gt;that are key-value objects&lt;/em&gt;) and merge their properties into a single Type, with the properties from both Types.&lt;/p&gt;

&lt;p&gt;Here is an example of what our implementation looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmynva19grtoe26wqd8ok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmynva19grtoe26wqd8ok.png" width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will go into the details of the above example, in a future issue (hopefully next week), as we explore Mapped Types and other Types in Typescript.&lt;/p&gt;

&lt;p&gt;To use our utility type, we just need to provide two object types and we get a single object with properties from both types that were passed in, as shown below:&lt;/p&gt;

&lt;p&gt;You can find the above code &lt;a href="https://www.typescriptlang.org/play?#code/C4TwDgpgBAshBOBzCB5ARgKwgY2AFXAgGcAeAQSggA9gIA7AEyKgCUcB7eBko4eASzqIANFACudANZ12AdzoA+UQCFKNek1YcuPPoJHipM+QoVQAvFADeAKCj2oAbQAK8dpHigogqJIgh2ADMoMgBdAC4Qxz8A4LCAbhsAXygAMms7Bxc3Dy8fGKCoZQii6P9C4sSkmxrQSChnBCJ2OgA5AEMAW2ILDIcoQP54Xg7uyN4BIUT+gBt2ka6Icb0p5NrCBqaWsmRe23725GXJxGmHBnY0Y-0q9frG4ZbeuCRUTBx8QlIH5rbFolEP22yAUNUCElw-CeFwAyuxusAABb6AAUgjAYmAkSBdAAlH0HOjMQA6Q4QZJAA" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our example above doesn’t do much, but let’s say that in the future the requirements of our project change and we want to expand it so that we can merge two or three types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahmvy133ty3m3vggyg5d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahmvy133ty3m3vggyg5d.png" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem is that this would work with merging 3 Types, but to work with merging two Types, we would need to provide an empty object Type, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8nylp59qhnefp936n27.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8nylp59qhnefp936n27.png" width="800" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wouldn’t be nice if we could skip that part, and just provide our two types? And this is where Generic type variable defaults come to the rescue.&lt;/p&gt;

&lt;p&gt;Just like function parameters, we can provide a default Type for our Type variable and essence making them optional, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxtltp2ryef7l8r3byew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxtltp2ryef7l8r3byew.png" width="800" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now, our &lt;code&gt;MergeObjectTypes&lt;/code&gt; utility type can accept either two or three Types and merge their properties into a single Type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkwfvige9fhgcfibhd3ab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkwfvige9fhgcfibhd3ab.png" width="800" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we can go crazy now and add more type variables to merge 4, 5, or 10 even object properties while ensuring our utility types work with 2 to 10 types, and anywhere in between.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are interested, see if you can modify the above example to work with 5 types.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Rules for Default Types
&lt;/h4&gt;

&lt;p&gt;Just like function parameters, there are a few rules to keep in mind for generic default Types.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The first and most obvious one is that when you provide a default value, a Type variable is deemed as optional.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are required to provide the required type variables.&lt;/li&gt;
&lt;li&gt;Remember, Type inference in most cases can help you, so you don’t provide the required Type variables.&lt;/li&gt;
&lt;li&gt;If you don’t provide an optional Type variable, then the default type is used, unless Typescript can infer a different type based on usage.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;And just for functions, required type variables come first, followed by optional type variables.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;If you are using a generics constraint, the default type must satisfy that constraint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhj3l2rfqbxri6w4c6afv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhj3l2rfqbxri6w4c6afv.png" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;For classes and interfaces, when extending either a class or an interface, you can introduce a default for an existing Type parameter and you may also introduce a new Typer variable, as long as it’s optional (has a type variable).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zusd4c63ethx2n5rliv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zusd4c63ethx2n5rliv.png" width="800" height="347"&gt;&lt;/a&gt;    &lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this issue, we looked at making generics Type variables optional by providing a default or fallback type. We drew parallels between Generics default types with functions parameters default values and how they behave almost the same, but with the key difference being one applies to variables while the other one applies to types.&lt;/p&gt;

&lt;p&gt;To demonstrate how useful default generics types can be, we took a look at an example where we can create a custom utility type that we can use to merge properties for an object type, for either two or three types, and how we can utilize defaults to make this work seamless for either of the cases.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Generic Constraints - A Gentle Introduction to Generics in Typescript</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Tue, 09 Apr 2024 07:43:40 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/generic-constraints-a-gentle-introduction-to-generics-in-typescript-i9b</link>
      <guid>https://dev.to/playfulprogramming/generic-constraints-a-gentle-introduction-to-generics-in-typescript-i9b</guid>
      <description>&lt;p&gt;In a &lt;a href="https://www.allthingstypescript.dev/p/a-gentle-introduction-to-generics" rel="noopener noreferrer"&gt;previous issue&lt;/a&gt;, we learned about the fundamentals of Generics in Typescript and how we can use generics to make our lives easier as developers. You can find the last issue &lt;a href="https://www.allthingstypescript.dev/p/a-gentle-introduction-to-generics" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But to quickly recap the last issue, Generics allows us to write our code in a way the data types we are dealing with will be specified later on. In Typescript, we do this using the type variable specified inside &lt;strong&gt;Angle&lt;/strong&gt; &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; &lt;strong&gt;brackets&lt;/strong&gt;, which we can then use within our application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A type variable&lt;/strong&gt; is a special kind of variable that works on types rather than values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is an example of a &lt;code&gt;sortArray&lt;/code&gt; function, that can sort any array, accepting a &lt;code&gt;SortType&lt;/code&gt; type variable, for the function input and output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccpmzg625dh0cya87dcd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccpmzg625dh0cya87dcd.png" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above functions sort generic functions, we need to specify the type of array we are sorting by providing the &lt;code&gt;SortType&lt;/code&gt; type variable, just before we provide the arguments for functions, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1k00xav4i07ckba4klw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1k00xav4i07ckba4klw.png" width="800" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this can be done for classes and when defining other types using either interface or type, to learn more, check out the previous issue &lt;a href="https://www.allthingstypescript.dev/p/a-gentle-introduction-to-generics" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are generic constraints?
&lt;/h3&gt;

&lt;p&gt;Before we can try and define generic constraining, let’s define the word constraint, on its own. Stay with me here, I know this is a Typescript newsletter, not an English newsletter and I am probably the worst person to teach English, considering it’s probably my third language. I digress anyway.&lt;/p&gt;

&lt;p&gt;According to the &lt;a href="https://dictionary.cambridge.org/dictionary/english/constraint" rel="noopener noreferrer"&gt;Cambridge Dictionary&lt;/a&gt; one of many definitions &lt;strong&gt;(I cherry-picked 🤷🏾)&lt;/strong&gt;, &lt;strong&gt;a constraint is something that controls what you do by keeping you within particular limits&lt;/strong&gt;. The key part I want you to remember for this issue is &lt;strong&gt;keeping you within particular limits&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Back to Typescript and Generics, if we looked at the previous example we had, our &lt;code&gt;sortArray&lt;/code&gt; function is meant to sort arrays, not other data types, which would probably require a different algorithm for arrays.&lt;/p&gt;

&lt;p&gt;However, our function will accept array types as well as non-array types, and this is not the desired behavior. This isn’t type-safe, as the function will probably throw a runtime error if we attempt to sort a string data type when we wrote it to sort arrays.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9730jbb5aaqn8nbqvnn9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9730jbb5aaqn8nbqvnn9.png" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typescript was meant to eliminate these kinds of errors, but we just made it even simpler to make them, and no way to know ahead of time.&lt;/p&gt;

&lt;p&gt;And this is where generics constraints come in. They enable us to limit (restrict or constrain) the types that can be provided for our type variables. This way, our function will accept arrays, but it will not accept non-array types. We do this by using the extends keyword and providing the types we want to contain our type variable to.&lt;/p&gt;

&lt;p&gt;For instance, in our &lt;code&gt;sortArray&lt;/code&gt; function, we can restrict our type variable to be only an array of &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, or &lt;code&gt;boolean&lt;/code&gt;, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpsb7lzn9iqkdam0jy0jz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpsb7lzn9iqkdam0jy0jz.png" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now, when we try to pass in a string, as we previously did, Typescript catches the type error for us, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foxem8f4c9huu9jf288dx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foxem8f4c9huu9jf288dx.png" width="800" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typescript now catches and warns us that we can not pass a &lt;code&gt;string&lt;/code&gt; type as the Type variable as it doesn’t satisfy the type constraint we provided. This works with Type inference too, as discussed in the previous issue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcuuclq8v7nm6vebkdw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcuuclq8v7nm6vebkdw6.png" width="800" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see generic constraints allow us to achieve type safety by restricting the Types for our application. By using Typescript generics constraints, we can now write our generics code knowing that we are dealing with a known pool of types rather than all types available. In our case, we are only dealing with arrays and not non-array types.&lt;/p&gt;

&lt;p&gt;In the previous example. we looked at constraining it to be an array, but we can constrain it to any type, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1ymfw6e08oo2dj2o7qb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1ymfw6e08oo2dj2o7qb.png" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the first case, we are constraining to only accept strings (and their subtypes), and in the second case, we want it to be a key-value object and in the last case, we are providing our type, to just demo the different ways you can constraint a Generic.&lt;/p&gt;

&lt;h4&gt;
  
  
  Type variable constrained by another Type Variable
&lt;/h4&gt;

&lt;p&gt;So far, we have dealt with simple but useful cases. I don’t want to go into some of the most advanced use cases of generics yet, because this is still a gentle introduction to generics but let’s look at another common scenario.&lt;/p&gt;

&lt;p&gt;For instance, let’s say we want to create a function that returns a property from a key-value object, given its key, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkfcxlmf4chhc1zhzsms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkfcxlmf4chhc1zhzsms.png" width="800" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we are using a Generic constraint to ensure that the first argument is always a key-value object, but we have a slight problem. We would like the second function argument - &lt;code&gt;key&lt;/code&gt; - to be only a key that exists inside the object we pass in. At the moment, we can pass anything and this could lead to undesired characteristics from our application.&lt;/p&gt;

&lt;p&gt;We can fix this issue by adding a second type variable that we can call &lt;code&gt;Key&lt;/code&gt; and whose type will be constrained to the keys of the object, for this we can use the &lt;code&gt;keyof&lt;/code&gt; operator to get the keys of the first type variable, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtrw5z8simaszcjnotth.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtrw5z8simaszcjnotth.png" width="800" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now, if you try to provide keys that aren’t present in the object in the first argument, Typescript will warn you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbdajcvi27i8j8k8r5f8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbdajcvi27i8j8k8r5f8.png" width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we get a warning when we provide a key that doesn’t exist and Typescript provides suggestions for keys you can use.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bonus
&lt;/h4&gt;

&lt;p&gt;There is one final thing we can do to make the function more complete and type-safe. As you can see, our function return type is unknown, which doesn’t tell us much and we would need to narrow it before using it. But we can use our type variables - the object and the key passed in, to look up the type of that property in the object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67o5mqwa2b12gee3dfta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67o5mqwa2b12gee3dfta.png" width="800" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, we are combining the type variables provided for the &lt;code&gt;getProperty&lt;/code&gt; function, where we are annotating the return type of the function to be the type of the property for the key provided.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4i5o8s9cwochfeeux0mn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4i5o8s9cwochfeeux0mn.png" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Typescript, this is known as indexed access types. Indexed access types allow us to look up specific properties of other types. You can learn more about this in a previous issue &lt;a href="https://www.allthingstypescript.dev/p/indexed-access-types-in-typescript" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you like my content and want to support my work, please consider supporting me (&lt;/strong&gt;&lt;em&gt;&lt;strong&gt;you can buy me a double latte, the juice that powers my creativity and determination ☕️&lt;/strong&gt;&lt;/em&gt;&lt;strong&gt;) through &lt;a href="https://github.com/sponsors/mainawycliffe/" rel="noopener noreferrer"&gt;Github Sponsors&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In today’s issue, we discussed generic constraints and why they are important in Typescript for increased type safety and improved developer experience. Generic constraints enable us to provide guard rails to the generics types so that we can be certain that the type of data that can be passed in is what is expected leading to enhanced type safety.&lt;/p&gt;

&lt;p&gt;This hasn’t been an easy issue to write, breaking down the concepts into something easy to understand and I hope you found it very illuminating.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Bun - The One Tool for All Your JavaScript/Typescript Project's Needs?</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Tue, 02 Apr 2024 17:27:06 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/bun-the-one-tool-for-all-your-javascripttypescript-projects-needs-5f13</link>
      <guid>https://dev.to/playfulprogramming/bun-the-one-tool-for-all-your-javascripttypescript-projects-needs-5f13</guid>
      <description>&lt;p&gt;In most issues for this newsletter, I have focussed on Typescript and its type system, which I will continue doing. This has been great for my readers (from the feedback I have received) but I have wanted to cover broader Typescript-related topics, such as today’s topic, after all this is All Things Typescript. I hope you will enjoy this topic and let me know if you want more like this.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Bun?
&lt;/h3&gt;

&lt;p&gt;NodeJS is the dominant Javascript server runtime environment for Javascript and Typescript (sort of) projects. But over the years, we have seen several attempts to build alternative runtime environments such as &lt;a href="https://deno.com/" rel="noopener noreferrer"&gt;Deno&lt;/a&gt; and Bun, today’s subject, among others.&lt;/p&gt;

&lt;p&gt;These newer alternatives focus on providing much better runtime performance, much better support for Web APIs on the server, and generally better security among other features, we will look at in later sections. The NodeJS team also continues to make improvements to NodeJS and we have seen tremendous improvements in here as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Develop, test, run, and bundle JavaScript &amp;amp; TypeScript projects—all with Bun. Bun is an all-in-one JavaScript runtime &amp;amp; toolkit designed for speed, complete with a bundler, &lt;a href="https://bun.sh/docs/cli/test" rel="noopener noreferrer"&gt;test runner&lt;/a&gt;, and Node.js-compatible &lt;a href="https://bun.sh/package-manager" rel="noopener noreferrer"&gt;package manager&lt;/a&gt;.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Compared to Deno, what I think makes Bun special, is that it’s a drop-in replacement for node (you don’t have to change much if anything at all). Unlike Deno which required you to make significant changes to your application at launch to adopt it, Bun doesn’t require you to make any changes to your codebase.&lt;/p&gt;

&lt;p&gt;With Bun, you can go into any node-js-based project, like let’s a Next JS or React Application, and just run &lt;code&gt;bun install&lt;/code&gt; (y_es, but install you read that correctly not npm install_) and then run the &lt;code&gt;bun run dev&lt;/code&gt; (&lt;em&gt;or whatever &lt;a href="https://docs.npmjs.com/cli/v9/using-npm/scripts" rel="noopener noreferrer"&gt;npm script&lt;/a&gt; you use to launch your project&lt;/em&gt;) and it should run your application, just like Node JS.&lt;/p&gt;

&lt;p&gt;From my experience, this ran flawlessly all the time I tried it.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, why use Bun?
&lt;/h3&gt;

&lt;p&gt;So, now that I have briefly introduced you to Bun and why it’s a very interesting project, let's see some of the advantages of using Bun, over Node (where most of us are probably coming from), and the others.&lt;/p&gt;

&lt;h4&gt;
  
  
  Speed, it’s Fast, Really Fast
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fva0lc2w0g305huxst9kw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fva0lc2w0g305huxst9kw.jpeg" width="631" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NodeJS is by no means a slow runtime, it wouldn’t be so popular if it was. But compared to Bun, it’s slow. Bun was built from the ground up with speed in mind, using both &lt;a href="https://developer.apple.com/documentation/javascriptcore" rel="noopener noreferrer"&gt;JavascriptCore&lt;/a&gt; and &lt;a href="https://ziglang.org/" rel="noopener noreferrer"&gt;Zig&lt;/a&gt;. The Bun team spent an enormous amount of time and energy trying to make Bun fast, including lots of profiling, benchmarking, and optimizations.&lt;/p&gt;

&lt;p&gt;Even the choice of the programming language to use Zig was done with performance in mind. The team chose Zig programming language as it allows them to have low-level control of memory management and lacks hidden control flow, making it easy to write fast software.&lt;/p&gt;

&lt;p&gt;The same can be said about the team’s decision to go with JavascriptCore. Both NodeJS and Deno are based on Chrome V8 Engine, while Bun is based on Apple's JavaScriptCore. While not mind-blowingly faster than the V8 Engine, it’s a little bit faster. And these optimizations have paid off for Bun, as it’s faster than both Deno and NodeJS.&lt;/p&gt;

&lt;p&gt;To demonstrate this I put my novice benchmarking skills to the test. To run the benchmarks, I used the latest versions of NodeJS, Deno, and Bun, as of the time of writing this issue.&lt;/p&gt;

&lt;p&gt;For benchmarking, I used the following simple JS code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for (let i = 0; i &amp;lt; 10000; i++) {
  console.log(`Count: ${i + 1}`);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then I used &lt;a href="https://github.com/sharkdp/hyperfine" rel="noopener noreferrer"&gt;hyperfine&lt;/a&gt; to run the benchmarks on my MacBook Pro 14 M2 Max, and here are the results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmopgx2iefyg6q0n1cur4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmopgx2iefyg6q0n1cur4.png" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, Bun is 2.20 faster than Deno and 2.88 faster than NodeJS. I also ran the same benchmarks on Windows 11 using WSL and Bun managed an even more impressive feat, being 3.06 times faster than node and 3.26 times faster than Deno, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtfjv6rlljmecujfb8ch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtfjv6rlljmecujfb8ch.png" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This benchmark was run on an Intel Core i9 11900H process and 40 GB of RAM&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤔 &lt;em&gt;&lt;strong&gt;Interestingly&lt;/strong&gt;, the Gap between NodeJS and Deno &lt;strong&gt;seems&lt;/strong&gt; to be closing, let me know in the comment section below if you want me to do a deep in dive comparing the three on different workloads and different OSs.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want to dig into the performance comparison and a very good explanation of the internal workings (in relationship to Javascript Engines) of NodeJS, check out this amazing video by &lt;a href="https://www.youtube.com/watch?v=8wTulvlllGQ" rel="noopener noreferrer"&gt;Chris Hay&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Compatibility with NodeJS and NPM
&lt;/h4&gt;

&lt;p&gt;I touched on this earlier, if you are already using NodeJS and would love to switch to Bun, you can do so with minimal effort. You can visit any NodeJS-based project, run &lt;code&gt;bun install&lt;/code&gt; and then run the server using Bun instead of NodeJS, no code changes are needed right out of the box.&lt;/p&gt;

&lt;p&gt;“Bun is designed as a drop-in replacement for Node.js. It natively implements hundreds of Node.js and Web APIs, including &lt;code&gt;fs&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;Buffer&lt;/code&gt; and more.”&lt;/p&gt;

&lt;p&gt;For more information on NodeJS APIs implemented by Bun &lt;a href="https://bun.sh/docs/runtime/nodejs-apis" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if all you just need is a much faster package manager, you can use Bun to replace NPM and use NodeJS for your server, no fuzz.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faavdxbmqpgt5o4v6btym.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faavdxbmqpgt5o4v6btym.png" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Built-in Tooling
&lt;/h4&gt;

&lt;p&gt;One of the most frustrating or overwhelming things especially for novices about modern web development is the amount of tools that you need to learn. For starters, you will need node/deno/bun and npm, and if you decide to use Typescript, you will need a transpiler and maybe (by maybe I mean, most certainly) a bundler and the story goes on.&lt;/p&gt;

&lt;p&gt;We, as web development veterans, sometimes forget how intimidating this can be for beginners, I guess you can call this Stockholm syndrome.&lt;/p&gt;

&lt;p&gt;With Bun, you only need Bun. It’s a drop-in replacement for all of the above tools above. Want to install packages, bun has got you, with Bun package manager, it’s a runtime and bundler and will transpile and run typescript code, without you having to install a host of tools to achieve the same.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnltz0euyb5xv6q2069q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnltz0euyb5xv6q2069q.jpeg" width="500" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What about testing? Yeah, Bun still got you with an inbuilt test-runner, goodbye Jest?🤷🏾. Bun is fully compatible with jest syntax and you can use it as a drop-in replacement for jest, and you get all the benefits of Bun discussed in this article.&lt;/p&gt;

&lt;p&gt;You can learn more about Bun testing &lt;a href="https://bun.sh/docs/cli/test" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Web Standard API
&lt;/h4&gt;

&lt;p&gt;One thing that serves as a divide depending on the runtime you are targeting is how some APIs are available on the browser, yet are missing on the server (NodeJS). This means that even for tasks you can perform in both the server and the browser, it’s possible to have two different APIs for achieving the same on both, despite the fact you using the same programming language.&lt;/p&gt;

&lt;p&gt;A good example of this, until recently, was fetch, a common task like fetching data over HTTP, which you can perform on both the browser and the server. It was natively supported in the browser environment but not supported natively by NodeJS. This can be frustrating because despite the fact you are writing Javascript, the tooling changes based on your target environment.&lt;/p&gt;

&lt;p&gt;Bun aims to address this by providing and implementing a list of standard web APIs that are similar to the ones available in the browser environment. Of course not all APIs available in the browser are required in the server environment, think of the DOM and History APIs as good examples of this.&lt;/p&gt;

&lt;p&gt;But common tasks in both environments such as making HTTP calls don’t need to have unique Web APIs for each environment. Bun implements the Web Standard APIs for some of this, instead of re-inventing the wheel, which makes our Job (especially full-stack developers) a tad bit easier.&lt;/p&gt;

&lt;p&gt;You can find a comprehensive list of Web Standard APIs implemented by Bun &lt;a href="https://bun.sh/docs/runtime/web-apis" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Supports Typescript and JSX/TSX out of the Box
&lt;/h4&gt;

&lt;p&gt;With Bun, you don’t need to transpile your Typescript code to Javascript to execute it (or result in using something ts-node). You can execute your Typescript directly using Bun, and it’s going to do all the heavy lifting for you - the process of transpilation, and executing the resulting JS code, without you having to think about it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One very important caveat&lt;/strong&gt;, that I missed before and I was corrected in the comment section below, is that Bun doesn’t perform type-checking, unlike other build tools, just does transpilation. You will still need the Typescript compiler to Typecheck your code.&lt;/p&gt;

&lt;p&gt;Bun treats TypeScript as a first-class citizen.&lt;/p&gt;

&lt;p&gt;On top of that, it does support JSX (TSX by extension) out of the box, compiling it internally to JS code ready for execution. In both cases, Bun will respect your configurations (&lt;code&gt;tsconfigs&lt;/code&gt;/&lt;code&gt;jsconfig&lt;/code&gt;) during the transpilation/conversion process.&lt;/p&gt;

&lt;p&gt;You can learn more about Typescript support &lt;a href="https://bun.sh/docs/runtime/typescript" rel="noopener noreferrer"&gt;here&lt;/a&gt; and JSX &lt;a href="https://bun.sh/docs/runtime/jsx" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Single File Executables
&lt;/h4&gt;

&lt;p&gt;Ever wanted to run compile your javascript into binary executables that you can run directly? Bun got your back here as well, you can compile Typescript and Javascript projects, including all dependencies into a single executable binary that you can distribute and run, without needing to install dependencies or even Bun itself.&lt;/p&gt;

&lt;p&gt;On top of that, you can embed files and even databases such as SQS Lite, if you want to. Please note, that if you embed SQL Lite, it runs in memory and the changes will be lost when the binary exists. This does give you several choices when it comes to distributing your projects, which doesn’t require the OS to have all the dependencies installed to run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bun Resources
&lt;/h3&gt;

&lt;p&gt;Let’s say you are interested in learning more about Bun and probably give it a try. Bun has a website, where you can learn more about Bun and its features (including all the benchmark data captured in this issue), and here is the &lt;a href="https://bun.sh/" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://bun.sh/docs" rel="noopener noreferrer"&gt;Bun Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://bun.sh/docs/installation" rel="noopener noreferrer"&gt;Installation Instructions&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.logrocket.com/getting-started-bun-react/" rel="noopener noreferrer"&gt;Getting started with Bun and React&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.freecodecamp.org/news/learn-bun-a-faster-node-js-alternative/" rel="noopener noreferrer"&gt;Learn Bun, a faster Node.js alternative&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this issue, I have done something different from my usual content. We have gone over Bun, a Javascript server runtime environment which is a drop-in replacement for NodeJS. We took a look at some of the features that set Bun apart from NodeJS and which might tempt you to switch to Bun.&lt;/p&gt;

&lt;p&gt;That’s it from me and until next time, keep on learning.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>bunjs</category>
      <category>typescript</category>
    </item>
    <item>
      <title>A Gentle Introduction to Generics in Typescript</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Tue, 26 Mar 2024 07:21:09 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/a-gentle-introduction-to-generics-in-typescript-3ap3</link>
      <guid>https://dev.to/playfulprogramming/a-gentle-introduction-to-generics-in-typescript-3ap3</guid>
      <description>&lt;p&gt;One of the more advanced topics in Typescript is Generics and understanding and adding them to your Typescript coding toolbox can be very powerful. As we continue with our journey of learning Typescript and building amazing projects, we want to have more and more tools that we can use to make our job easier, without making compromises when possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are generics?
&lt;/h3&gt;

&lt;p&gt;Let’s see a useful case on why generics can be very important and even crucial. Let’s say we want to build a function to sort strings. It would look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function sortString(str: string[]): string[] {
    // sort algorithm
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But after a while, the requirements of our project change, and we need to be able to sort numbers as well. The algorithm to sort the strings and numbers is the same but to have it strongly typed we would need to create a second function for that as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function sortNumber(num: number[]): number[] {
    // sort algorithm
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the future, the requirements of our project could change and we could end up sorting different types of variables. As you can see, we could end up duplicating the original function, more and more, as we need to be able to sort different types of arrays.&lt;/p&gt;

&lt;h4&gt;
  
  
  Can we use the &lt;code&gt;any&lt;/code&gt; Type to solve this problem
&lt;/h4&gt;

&lt;p&gt;Yes, we could. But this comes with one huge disadvantage, compared to having multiple functions, we lose type-safety and type precision, and we certainly don’t want this.&lt;/p&gt;

&lt;p&gt;You can learn more about why you should avoid using the &lt;code&gt;any&lt;/code&gt; type in one of my previous issues &lt;a href="https://www.allthingstypescript.dev/p/why-avoid-the-any-type-in-typescript" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function sort(num: any[]): any[] {
//                  ^ DON'T DO THIS
    // sort algorithm
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Is there a better solution?
&lt;/h4&gt;

&lt;p&gt;Before I can answer that, let’s recap. &lt;em&gt;So, we want a solution that allows us to write a single sort function, without compromising type-safety and losing type precision&lt;/em&gt;. Back to the question, yes, there is a better solution.&lt;/p&gt;

&lt;p&gt;What if, instead of writing a sort function with static types for arguments and return values as we did previously, we could write a function whose types can be specified when the function is being called?&lt;/p&gt;

&lt;p&gt;So, in our case, we would allow the caller of our sort function to specify the type of function &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments" rel="noopener noreferrer"&gt;argument&lt;/a&gt; (the array to be sorted) and output (sorted array).&lt;/p&gt;

&lt;p&gt;This is exactly what generics allow us to achieve in programming, and &lt;a href="https://en.wikipedia.org/wiki/Generic_programming" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt; has a very good definition of it.&lt;/p&gt;

&lt;p&gt;Generic programming is a style of computer programming in which algorithms are written in terms of data types to-be-specified-later that are then instantiated when needed for specific types provided as parameters.&lt;/p&gt;

&lt;p&gt;To break the above down in relationship to our sort function requirement, we want to write our sort function algorithm, without tying that algorithm to a specific type - &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt;, etc. but also allow the caller to let us know the type that we can use for type-checking.&lt;/p&gt;

&lt;h4&gt;
  
  
  So, how do they work?
&lt;/h4&gt;

&lt;p&gt;In Typescript, we use generics by providing the type variable inside angle brackets (&lt;code&gt;&amp;lt;Type&amp;gt;&lt;/code&gt;). A type variable is a special kind of variable that works on types rather than values. You have free reign in naming the type variables, just like the naming of other variables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5qr18fvgspk09k2k96m.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5qr18fvgspk09k2k96m.jpeg" width="600" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For instance, in functions, we provide the type variable, in angle brackets (&lt;code&gt;&amp;lt;Type&amp;gt;&lt;/code&gt;), in between the function name and brackets used to specify the arguments. We will see about generic classes, types, and interfaces later on. The type specified here can then be used within the function, or for arguments and return types, as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function sort&amp;lt;SortType&amp;gt;(genericInput: SortType[]): SortType[] {
~~~~~~~~~~~~~~   ^ Type Variable
    return genericInput.sort();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above function, we are specifying the type variable, which is the &lt;code&gt;SortType&lt;/code&gt; type, and then for the function argument, we use &lt;code&gt;SortType&lt;/code&gt; as the type of the first function argument and output. And this is how we use the above function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const x = sort&amp;lt;string&amp;gt;(["1", "2", "3"]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are providing the string type, as the type variable and now Typescript can use the information to type-check the function arguments and outputs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbqgabaksjrm53lb4xjc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbqgabaksjrm53lb4xjc.png" width="357" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This works for a variety of types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const nums = sort&amp;lt;number&amp;gt;([1, 2, 4, 5])
//            ^? function sort(input: number[]): number[]

const str = sort&amp;lt;string&amp;gt;(["str", "str2"])
//            ^? function sort(input: string[]): string

// we can even mix up things now
const both = sort&amp;lt;string | number&amp;gt;([1, 2, "str"])
//            ^? function sort(input: (string | number)[]): (string | number)[]     
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we try a different type other than the one provided in our generic type variable, Typescript is going to throw an error, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdq9mxa01cwgr8k7h0ad1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdq9mxa01cwgr8k7h0ad1.png" width="778" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Typescript will type-check the function arguments against the Type variable we provided.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And just like functions arguments, you can have multiple type variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function manyGenerics&amp;lt;A, B, C, D&amp;gt;(a: A, b: B, c: C, d: D): [A, B, C, D] {
    return [a,b,c,d]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4umcf6ty11aivntn0mm.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4umcf6ty11aivntn0mm.jpeg" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Do I have to provide the type variable every time?
&lt;/h4&gt;

&lt;p&gt;The answer is no, and this is because Typescript can use Type &lt;a href="https://www.allthingstypescript.dev/p/all-things-typescript-newsletter-issue-13-type-inference-in-typescript-1211063" rel="noopener noreferrer"&gt;inference&lt;/a&gt; so you don’t have to provide the functions generic type with every call.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ippn3j5lsk3hddwsk6f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ippn3j5lsk3hddwsk6f.png" width="564" height="61"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typescript will use the type inferred for our generic input, as the type for our variable type, which can save you from having to always specify the type variable.&lt;/p&gt;

&lt;p&gt;This is so good that many developers use generics daily without realizing it. For instance, the &lt;code&gt;Array.sort()&lt;/code&gt; functions and other &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array" rel="noopener noreferrer"&gt;Array methods&lt;/a&gt; are generic functions.&lt;/p&gt;

&lt;p&gt;For instance, the following &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map" rel="noopener noreferrer"&gt;Array.map&lt;/a&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 5, 3, 11, 6 ].map(x =&amp;gt; x.toString());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can also be written like this, with the type variable provided.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 5, 3, 11, 6].map&amp;lt;string&amp;gt;(x =&amp;gt; x.toString());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Where else can we use generics?
&lt;/h3&gt;

&lt;p&gt;So far, we have seen generics in function space. But we can use generic in a variety of places, not just functions. Let’s see some of this:&lt;/p&gt;

&lt;h4&gt;
  
  
  Classes and Methods
&lt;/h4&gt;

&lt;p&gt;Just like functions, when defining a class, we can request a type variable(s) for the class, which we can then use within the class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class SomeClass&amp;lt;Type&amp;gt;{
// ~~~~~~~~~~~~~ ^ Type Variable

    property: Type;
    //         ^ We can use the Generic type for types of properties

    doSomething(input: Type): Type {
    //                  ^ and for methods input
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on top of that, we can provide type variables for the methods themselves, if need be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class SomeClass{
    doSomething&amp;lt;Type&amp;gt;(input: Type): Type {
        //       ^? Type Variable
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Types and Interfaces Definition for Key-Value Objects
&lt;/h4&gt;

&lt;p&gt;When defining types for key-value objects using either &lt;a href="https://www.allthingstypescript.dev/p/type-vs-interface-in-typescript-all" rel="noopener noreferrer"&gt;interface or type&lt;/a&gt;, you can use generics to provide types for some of the properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Person&amp;lt;Type&amp;gt; = {
//            ^ Type Variable
    name: string;
    id: string;
    properties: Type;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can do the same with interfaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Person&amp;lt;Type&amp;gt; {
//                ^ Type Variable
    name: string;
    id: string;
    properties: Type;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What’s next?
&lt;/h3&gt;

&lt;p&gt;So far, we have had a very brief introduction to Typescript generics, where we looked at creating Generics in Typescript and how we can use them. Generics are powerful and are very useful and in our latest issue, we looked at constraining our generic types, here is the &lt;a href="https://www.allthingstypescript.dev/p/generic-constraints-a-gentle-introduction" rel="noopener noreferrer"&gt;issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See you next week and &lt;a href="https://www.allthingstypescript.dev/" rel="noopener noreferrer"&gt;subscribe&lt;/a&gt; to not miss the next issue.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you like my content and want to support my work, please consider supporting me (&lt;/strong&gt;&lt;em&gt;&lt;strong&gt;you can buy me a double latte, the juice that powers my creativity and determination ☕️&lt;/strong&gt;&lt;/em&gt;&lt;strong&gt;) through &lt;a href="https://github.com/sponsors/mainawycliffe/" rel="noopener noreferrer"&gt;Github Sponsors&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/sponsors/mainawycliffe/" rel="noopener noreferrer"&gt;☕️ Consider buying me a cup of coffee&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this issue, we looked at Typescript generics. We looked at a simple example of a sorting function, that enabled us to see in which situations generics can be very useful and how generics can help us write less code without compromising type safety.&lt;/p&gt;

&lt;p&gt;In the next issue, we will continue looking at generics and some advanced techniques that we can do with generics to even lead to more Type safety.&lt;/p&gt;

&lt;p&gt;So, until next, keep on learning.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A Deep Dive into the satisfies operator in Typescript</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Tue, 12 Mar 2024 19:36:44 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/a-deep-dive-into-the-satisfies-operator-in-typescript-1b3n</link>
      <guid>https://dev.to/playfulprogramming/a-deep-dive-into-the-satisfies-operator-in-typescript-1b3n</guid>
      <description>&lt;p&gt;In Typescript &lt;a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html" rel="noopener noreferrer"&gt;version 4.9&lt;/a&gt;, Typescript introduced the satisfies operator. Over the last few months, I have seen examples of it being used out in the world more often, and even I have found myself getting comfortable using it. In this issue, I want to do a deep dive and try and answer the following questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Why it exists&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why not annotations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why not assertions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When to use it&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What is the &lt;code&gt;satisfies&lt;/code&gt; Typescript operator
&lt;/h3&gt;

&lt;p&gt;According to the Typescript &lt;a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html" rel="noopener noreferrer"&gt;docs&lt;/a&gt;, the new &lt;code&gt;satisfies&lt;/code&gt; operator lets us validate that the type of an expression matches some type, without changing the resulting type of that expression.&lt;/p&gt;

&lt;p&gt;So, what does this mean? When we add type annotations to a variable, Typescript doesn’t usually infer the Type to its narrowest possible value. So, if we say a variable’s type is a string, Typescript takes our word for it and checks the value we assign to it against the type annotation we provided, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const str: string = "hello"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the case above, despite us using const, and having all the information at hand to narrow the above type to the &lt;code&gt;hello&lt;/code&gt; literal type, Typescript doesn’t do that and instead takes our annotation as the type of the variable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff44987s6nrmouertn4g4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff44987s6nrmouertn4g4.png" width="337" height="97"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is in contrast to when we allow type inference to work for us, instead of explicitly providing Type annotations, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhndy15pgj2p88ukgxzg5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhndy15pgj2p88ukgxzg5.png" width="334" height="80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see from the above example, when we use explicit type annotations, we lose the narrower type that we would have gotten if we had let Typescript infer the type for us.&lt;/p&gt;

&lt;p&gt;Why is this important, you may ask? To answer this, let me show you an example, take the following two functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function a(input: string) {
  // do something
}

function b(input: "hello") {
  // do something 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first function accepts a string and the second accepts a literal type - &lt;code&gt;hello&lt;/code&gt;. With the first variable, we annotated the type explicitly, this can be passed to the first function without any issues.&lt;/p&gt;

&lt;p&gt;But in the second function, despite the first variable value being hello, Typescript will make you jump through to accept the variable, simply because it expects a narrower type than the type of string we provided.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dd6v9ankclsm55pbtp9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dd6v9ankclsm55pbtp9.png" width="725" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the second function, you would need to narrow the variable for it to work, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if(str === "hello")  b(str);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In our case above, we are using control flow to narrow the type of str variable to hello, from a broader type of string. You can learn more about type narrowing in this previous &lt;a href="https://www.allthingstypescript.dev/p/narrowing-types-in-typescript" rel="noopener noreferrer"&gt;issue&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  How does the &lt;code&gt;satisfies&lt;/code&gt; operator help?
&lt;/h4&gt;

&lt;p&gt;If you are wondering what this has to do with the satisfies operator, I am getting to the point in a moment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fss17bo2rp5jazsvdm0rp.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fss17bo2rp5jazsvdm0rp.jpeg" width="500" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What if you wanted to ensure that &lt;code&gt;str&lt;/code&gt; is a string, without losing the narrowness of the inferred type? If you remember at the beginning, we said that the satisfies operator allows you to validate (think type-check) a variable type without changing the resulting type of that expression. The &lt;strong&gt;resulting type&lt;/strong&gt; being the Type inferred by Typescript in the absence of explicit type annotation.&lt;/p&gt;

&lt;p&gt;So, if we went back to our example, instead of using type annotation for our variable, and instead we used the &lt;code&gt;satisfies&lt;/code&gt; operator, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const str = "hello" satisfies string;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our variable wouldn’t carry the type of string as it did previously when we used type annotations, but the resulting inferred type is retained.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhrsjrifa47ks8ox7jg4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhrsjrifa47ks8ox7jg4.png" width="381" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this means, we can now pass the variable to the second function without needing to narrow the type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const str = "hello" satisfies string;
//    ^? type = "hello"

// this works now
b(str);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  “Real-world” Example
&lt;/h4&gt;

&lt;p&gt;Okay, I know what you are thinking, this isn’t a practical example. And that’s true, but I needed a straightforward example, that hopefully was easy to follow and understand, which I hope worked, and if it didn’t let me know in the comment section below.&lt;/p&gt;

&lt;p&gt;Let’s see a more realistic example. Let’s say we want an object, with property names being &lt;code&gt;string&lt;/code&gt; and values being either &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, or &lt;code&gt;boolean&lt;/code&gt;, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const user = {
    firstName: "John",
    lastName: "Doe",
    age: 5,
    isMember: true
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the above object, we might want to have Typescript type-check the content of the object. In such a situation we have two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;providing explicit type annotations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;or the &lt;code&gt;satisfies&lt;/code&gt; operator.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we use type annotations and try accessing one of the properties, Typescript doesn’t know the properties that are inside the object or their types, this is despite us explicitly adding them and adding them upfront.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const user: Record&amp;lt;string, string | number | boolean&amp;gt; = {
    firstName: "John",
    lastName: "Doe",
    age: 5,
    isMember: true
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, Typescript goes with the type from our Type annotation for the property values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpf26ifxz93tds2bbln5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpf26ifxz93tds2bbln5a.png" width="525" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This isn’t great, for one, we can include properties that don’t exist inside our user object or typos and which may introduce bugs within our codebase. However, if we went with the &lt;code&gt;satisfies&lt;/code&gt; operator, then things work out quite differently and for the better.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const user = {
    firstName: "John",
    lastName: "Doe",
    age: 5,
} satisfies Record&amp;lt;string, string | number | boolean&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we try and access the property firstName, we get both auto-completion 👌🏾 and it has the correct type, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9255zruem2ahmj6m031t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9255zruem2ahmj6m031t.png" width="499" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also can’t access properties we didn’t explicitly add to the user object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F145ymbkungnxfvn12bhu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F145ymbkungnxfvn12bhu.png" width="800" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we also get the excess property checking we got when we provided explicit type annotations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucgkdx9a25abe0nbncww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucgkdx9a25abe0nbncww.png" width="633" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This has a few benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Improved type safety as demonstrated in the last example. This is twofold:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validating the object properties and values are of certain types, and&lt;/li&gt;
&lt;li&gt;avoiding changing the objects’ inferred type, which means the property value types are narrow instead of wide.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Reduced the amount of code we write - we don’t need to engage in type narrowing to use our properties above, they already have a narrow type.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Use Cases
&lt;/h4&gt;

&lt;p&gt;Now that we have seen how we can some of the use cases of the &lt;code&gt;satisfies&lt;/code&gt; operator.&lt;/p&gt;

&lt;h5&gt;
  
  
  Constraining the type of variable
&lt;/h5&gt;

&lt;p&gt;We can use the satisfies operator to constrain or limit the types that can be used for a variable, without interfering with the type inference. A good example of this is our example above, where we limited our variable &lt;code&gt;str&lt;/code&gt; to string, but let it be inferred as a narrower type by typescript, using the available information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const str = "hello" satisfies string;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Constraining the Property Names of an Object and Catching Excess Properties
&lt;/h5&gt;

&lt;p&gt;We can use the &lt;code&gt;satisfies&lt;/code&gt; operator to make sure our object only has the keys and nothing extra.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Circle = {
  shape: "circle";
  radius: number;
}

const circle = {
  shape: "circle",
  radius: 4,
  anotherKey: 4
  // this will throw an error as shown bolow
} satisfies Circle;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsul0ic4jnm06gvaki99w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsul0ic4jnm06gvaki99w.png" width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Constraining the values of Properties, the opposite of the above
&lt;/h5&gt;

&lt;p&gt;The following will throw an error because the shape property is missing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const circle = {
  radius: 4,
} satisfies Record&amp;lt;any, number&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Ensuring an Interface is Implemented
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Person {
  delete: () =&amp;gt; void;
  get: () =&amp;gt; Record&amp;lt;string, unknown&amp;gt;
}

const thisPersion = {
  delete:  () =&amp;gt; {};
  get: () =&amp;gt; ({})
} satisfies Person;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more about the &lt;code&gt;satisfies&lt;/code&gt; operator, check out the following &lt;a href="https://github.com/microsoft/TypeScript/issues/47920" rel="noopener noreferrer"&gt;issue&lt;/a&gt;, where the discussion for adding the satisfies operator to Typescript happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this issue, we took a look at the &lt;code&gt;satisfies&lt;/code&gt; Typescript operator, and how it can be used to validate a type, without changing the inferred type of the expression. This is different from how both type assertions and annotations work because Typescript takes that as the type of the object, which is sometimes not desired.&lt;/p&gt;

&lt;p&gt;When using the &lt;code&gt;satisfies&lt;/code&gt; operator, Typescript only type-checks our variable against the provided type while inferring the type using the information available (Learn more about Type Widening here).&lt;/p&gt;

&lt;p&gt;The inferred type is usually narrower, meaning it can be used without the need for narrowing, which may not be the case for using assertions and annotations, while also type-checking it against a specific type, which ensures type safety isn’t compromised.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you loved today’s content and would be interested in supporting my work, please consider supporting me (&lt;/strong&gt;&lt;em&gt;&lt;strong&gt;you can buy me a double latte, the juice that powers my creativity ☕️&lt;/strong&gt;&lt;/em&gt;&lt;strong&gt;) through &lt;a href="https://github.com/sponsors/mainawycliffe/" rel="noopener noreferrer"&gt;Github Sponsors&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Boost your productivity by mastering Oh My ZSH git aliases</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Wed, 06 Mar 2024 07:03:05 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/boost-your-productivity-by-mastering-oh-my-zsh-git-aliases-4i10</link>
      <guid>https://dev.to/playfulprogramming/boost-your-productivity-by-mastering-oh-my-zsh-git-aliases-4i10</guid>
      <description>&lt;p&gt;Since I discovered Oh My Zsh a few years ago, it has been a god-sent gift to me. I believe it has impacted my productivity in a very positive way, for instance, with the history autocomplete plugin, I no longer have to keep hitting the up arrow until I get to the command I wanted, I can just start typing and Oh My Zsh will give me suggestion s based on my history. It’s just genius.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PS: If you are looking to get started with Oh My Zsh, you can find the installation instructions &lt;a href="https://github.com/ohmyzsh/ohmyzsh/wiki" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhv2ghg3suf78cebjz8m.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhv2ghg3suf78cebjz8m.jpeg" width="531" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I guess this is the one plugin I can probably not survive with, my flailing memory would suffer greatly to have to remember all my previous commands, even the ones I worked out myself. A close second plugin for my workflow and I believe vital for most developers is the git plugin. It’s just genius.&lt;/p&gt;

&lt;p&gt;Subscribed&lt;/p&gt;

&lt;p&gt;Of course, with Oh My Zsh, you have an arsenal of plugins that you can call upon to do your bidding, such as the docker, node, and npm, to mention a few. You can learn more about Oh My Zsh plugins (installation and list of plugins) in the official wiki &lt;a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a long time, I and the git plugin, have become very close buddies. Want to rebase, push (force push), pull, etc, the plugin will autocomplete everything for you including the git branches, I never get the spelling right on the first try, heck I am even known for copy-pasting them.&lt;/p&gt;

&lt;p&gt;I even adapted my naming of git branches, starting with the issue number, followed by the title slug so that I can get even faster autocomplete. Don’t even ask what I was naming them before.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1oa7se4fut01z7qlyks.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1oa7se4fut01z7qlyks.jpeg" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I digress&lt;/p&gt;

&lt;h3&gt;
  
  
  Oh My Zsh Git Aliases
&lt;/h3&gt;

&lt;p&gt;A few months ago, I came across Oh My Zsh git aliases, and well this has transformed my workflow. I can type into my terminal a combination of letters (3 to 5 characters, sometimes 6) and accomplish the same thing I did with a whole sentence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0j81f8zoavcgspn2uw4.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0j81f8zoavcgspn2uw4.jpeg" width="500" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I know, we as developers have been accused of being overpaid 🤷🏾 and lazy and I am playing up to my character incredibly well here. I will take any shortcut I can to do more, by doing less. On the other hand, I am a huge fan of a good developer experience and I will put anything in my toolbox that improves it, including Github Copilot - I guess I owe another article here as well.&lt;/p&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;p&gt;To show you what I mean, I will demonstrate why I am a huge fan of Git Aliases and why you should start using them. First, with the command that I have always had many struggles with, not because I can’t memorize it, but because I have to remember the branch name - &lt;code&gt;git push -f branch-name&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you work with Git issues, you probably create branch names for your issues, which could be anything. So, after a rebase against your main branch, you need to push the changes remotely to the PR (for those of us using Github, but there are equivalents for other remove hosting services such as Gitlab), so you need to type the above command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -f whatever-the-****-your-branch-name-is
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have Oh My Zsh and the Git Plugin, you will probably use it to autocomplete the branch name you want to force push, which is quite helpful. But you can make your life even more easier by using the following git alias:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ggf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, it’s that simple and will force-push your current branch without you having to worry whether you got the correct branch name or not (&lt;em&gt;god forbid you are not force-pushing on the main branch&lt;/em&gt; 🙈). Magic. Now imagine this, you have a few branches that are behind that you want to rebase and force push remotely. This does make your life a little bit easier, doesn’t it?&lt;/p&gt;

&lt;p&gt;And did I mention, that it even makes rebasing way easier? So, let’s say, you notice that your branch is behind the origin main branch, instead of checking out the main branch and pulling the changes, you can simply fetch the remote main and merge your branch against it, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git fetch origin
git rebase origin/main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you think typing the above is a lot of work, like me, you can simplify that by using the following Git Aliasis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gfo &amp;amp;&amp;amp; grbom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above two aliases will fetch the origin branches and rebase the current branch against the origin main branch. And now you can simply run &lt;code&gt;ggf&lt;/code&gt; to force push remotely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foabz4qvrn9ezv6efxfpn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foabz4qvrn9ezv6efxfpn.gif" width="360" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Impressed?&lt;/p&gt;

&lt;p&gt;Yes, there is a learning curve, of course, you have to memorize the above Aliases, nothing good comes for free. But I believe it’s worth it and they will come naturally to you with time.&lt;/p&gt;

&lt;p&gt;Another thing I want to emphasize is that as you go on your way to memorizing and becoming a 10x lazier developer, learn the underlying Git commands, and understand what each Alias you use maps to and what the command does, this way, you will know when not to use an Alias and when to find a different one.&lt;/p&gt;

&lt;p&gt;So, if you hear me and want to start using Git Aliases with Oh My Zsh, where do I start? Here are some of the most useful links to installing Oh My Zsh and a cheat sheet for the Aliases to help you memorize them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/ohmyzsh/ohmyzsh/wiki" rel="noopener noreferrer"&gt;Installing Oh My Zsh&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://kapeli.com/cheat_sheets/Oh-My-Zsh_Git.docset/Contents/Resources/Documents/index" rel="noopener noreferrer"&gt;Oh-My-Zsh Git Cheat Sheet - Kapeli&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins" rel="noopener noreferrer"&gt;Plugins Wiki&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this post, we took a look at how can use Oh My ZSH git aliases to boost our productivity and improve our developer experience, With git aliases we can accomplish more while writing less, this is especially useful when performing rebates and pushing changes across multiple branches where the actions are compressed into just a few characters.&lt;/p&gt;

&lt;p&gt;I hope this post convinced you to add Git Aliases to your developer toolbox.&lt;/p&gt;

&lt;p&gt;Thank you for reading and until next time, keep on learning.&lt;/p&gt;

</description>
      <category>tooling</category>
      <category>git</category>
      <category>devex</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A deep dive into new control flow syntax for Angular (17)</title>
      <dc:creator>Maina Wycliffe</dc:creator>
      <pubDate>Mon, 20 Nov 2023 15:18:19 +0000</pubDate>
      <link>https://dev.to/playfulprogramming-angular/a-deep-dive-into-new-control-flow-syntax-for-angular-17-24ld</link>
      <guid>https://dev.to/playfulprogramming-angular/a-deep-dive-into-new-control-flow-syntax-for-angular-17-24ld</guid>
      <description>&lt;p&gt;With the release of Angular 17, I wanted to explore the control flow syntax in Angular and demonstrate its benefits. The new syntax, which was part of the release for v17 of Angular, alongside a torn of other features we are going to look at in the future, is a big deal and a huge departure from how we accomplished control flow in Angular.&lt;/p&gt;

&lt;p&gt;Control flow is the order in which statements are executed by the computer in a script. We can use conditions (&lt;code&gt;if…else, switch&lt;/code&gt; statements) to determine which statements to execute and which to skip when certain conditions are met. We can even repeatedly execute statements using loops.&lt;/p&gt;

&lt;p&gt;Subscribed&lt;/p&gt;

&lt;p&gt;Angular is getting a new syntax for control flow, a major departure from what things were (I will refer to it as the old syntax), and still are, as the new control flow syntax is still in the developer preview.&lt;/p&gt;

&lt;p&gt;First, let’s compare the new syntax with the old syntax.&lt;/p&gt;

&lt;h4&gt;
  
  
  If Conditions
&lt;/h4&gt;

&lt;p&gt;Let’s say we want to show a section of our template if the conditions are true. With the old syntax, we would do it like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrsljnt8g2idqd7nvv7l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrsljnt8g2idqd7nvv7l.png" width="800" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Old if….else conditional syntax in Angular&lt;/p&gt;

&lt;p&gt;But now, with the all-new syntax, this would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0b6bdikw75285buvnpn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0b6bdikw75285buvnpn5.png" width="554" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New Angular if…else conditional syntax&lt;/p&gt;

&lt;p&gt;Or can be further simplified to:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu89iskj27au2rbtpttcx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu89iskj27au2rbtpttcx.png" width="432" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  For Loop
&lt;/h4&gt;

&lt;p&gt;What about for loops:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Old&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2Fw_1456%2Cc_limit%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F71395fc2-04cc-41e6-9921-f2eb8c8fba32_538x308.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2Fw_1456%2Cc_limit%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F71395fc2-04cc-41e6-9921-f2eb8c8fba32_538x308.png" title="Angular Old For Loop Syntax" alt="Angular Old For Loop Syntax" width="538" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For Loop before V17&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi032pux1mzg3bzx708f2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi032pux1mzg3bzx708f2.png" width="561" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New Angular For Loop Syntax&lt;/p&gt;

&lt;p&gt;As you can see, we are also passing a tracking expression that yields a unique key that we can use to associate the array items and their place in the DOM for performance reasons. This is required in the new control flow syntax, while before with the old syntax, it was optional.&lt;/p&gt;

&lt;h4&gt;
  
  
  NgSwitch
&lt;/h4&gt;

&lt;p&gt;Here is an example of the old syntax&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe738mtpfmhf2jglk5l0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe738mtpfmhf2jglk5l0g.png" width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is what that looks like now, with the new syntax&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqcp0k4yf5bx0m4nxf9ib.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqcp0k4yf5bx0m4nxf9ib.png" width="690" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice something? The new syntax is more readable (I know, it’s subjective, but I think we can both subjectively agree) and familiar, it looks like the very familiar syntax you would come across while writing Typescript or Javascript (or most languages for that matter). If you are new to Angular, good luck understanding the old syntax without a few head scratches and squinting your eyes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn7zcjdo8xkfodvurk61v.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn7zcjdo8xkfodvurk61v.jpeg" width="577" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then there is another huge benefit, &lt;strong&gt;syntax highlighting and formatting&lt;/strong&gt;. In the old syntax, we didn’t have much in the syntax highlighting corner, as the structural directive we part of the HTML attribute. Since now the control flow isn’t part of the HTML tags, syntax highlighting is already available. On top of that, the prettier npm package (update to the latest version) now supports formatting of the new Angular syntax and it’s just glorious.&lt;/p&gt;

&lt;p&gt;Combine these two, and you can now easily tell where one block ends and the other one starts and any nested blocks within the template are easy to identify. This should aid in code readability and improve it exponentially.&lt;/p&gt;

&lt;p&gt;And did I mention there is no more unnecessary &lt;code&gt;ng-container&lt;/code&gt; and &lt;code&gt;ng-template&lt;/code&gt; for conditional HTML blocks? This leads to much cleaner code with less boilerplate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2sbp33dcjgupk3soji0w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2sbp33dcjgupk3soji0w.jpeg" width="620" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wish things were that simple&lt;/p&gt;

&lt;p&gt;So far we have seen if and for syntaxes, what about the switch, here is an example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improvements over the Old Syntax
&lt;/h3&gt;

&lt;h4&gt;
  
  
  → for loop: required track expression
&lt;/h4&gt;

&lt;p&gt;With the new syntax, providing a track expression that yields a key to keep track of each item in the array to the view location in the DOM for improved performance, especially over large lists is required.&lt;/p&gt;

&lt;p&gt;Trying to leave it out, you get the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@for loop must have a "track" expression
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On top of that, Angular is using a new optimized algorithm for the for loop so that it’s more performant by making DOM operations as a response to collection changes minimal and hence more efficient.&lt;/p&gt;

&lt;h4&gt;
  
  
  → for loop &lt;a class="mentioned-user" href="https://dev.to/empty"&gt;@empty&lt;/a&gt; Keyword
&lt;/h4&gt;

&lt;p&gt;On top of that, we now have an &lt;code&gt;@empty&lt;/code&gt; keyword that we can use to handle situations where the list is empty, which is kind of neat.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0lyyye53j4fka4xhihxa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0lyyye53j4fka4xhihxa.png" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  → readable else
&lt;/h3&gt;

&lt;p&gt;As we saw earlier, doing else in the old control flow syntax in Angular was not really readable and required a lot of boilerplate code, however with the new control flow, it’s much more readable and more familiar, especially for developers just starting out in Angular.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0b6bdikw75285buvnpn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0b6bdikw75285buvnpn5.png" width="554" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What about the Async Pipe?
&lt;/h3&gt;

&lt;p&gt;Just like before, we can still the async pipe to subscribe to observables just like before.&lt;/p&gt;

&lt;p&gt;Within for loops, this is how we can achieve this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4tt8e5hbyvxq4i6hrsf8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4tt8e5hbyvxq4i6hrsf8.png" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same can be done for the if blocks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi7yu6eczurhzuoiq2z0t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi7yu6eczurhzuoiq2z0t.png" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  I am sold, how do I switch?
&lt;/h3&gt;

&lt;p&gt;First, make sure you have updated your Angular project to v17 and then you can run the following schematic to convert existing control flow syntax to the new control flow syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng g @angular/core:control-flow-migration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted for a path, enter the path to your project and that’s it.&lt;/p&gt;

&lt;p&gt;A word of caution, which is a huge step forward in Angular, is that the control flow syntax is in the &lt;a href="https://angular.io/guide/releases#developer-preview" rel="noopener noreferrer"&gt;developer preview&lt;/a&gt;. This means some things may change under the hood without following semantic versioning, as it gives the Angular team flexibility to move first and fix issues and concerns that may arise before it’s generally available with the same &lt;a href="https://angular.io/guide/releases" rel="noopener noreferrer"&gt;guarantees Angular&lt;/a&gt; provides for all its features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next on Unstacked: The all-new &lt;a class="mentioned-user" href="https://dev.to/defer"&gt;@defer&lt;/a&gt; syntax
&lt;/h3&gt;

&lt;p&gt;On top of that, Angular is getting a new &lt;code&gt;@defer&lt;/code&gt; syntax that can be used to lazy load components, directives, and pipes in the template, until certain conditions are met. I am going to go over this in the next issue of Unstacked in the next couple of weeks as this post is becoming overly long for a newsletter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this post, we took a look at the new control flow syntax for angular and the benefits it brings along as compared to the old syntax. We learned that the new control flow syntax is more familiar and subjectively more readable as compared to the old one, and requires less mental gymnastics to understand what’s going on, even for experienced Angular devs, let alone newbies. We also learned how the new syntax not only replaces the old syntax but improves upon it by bringing in extra helpers such as &lt;code&gt;@empty&lt;/code&gt; and required track by expression for improved performance.&lt;/p&gt;

&lt;p&gt;That’s it from me, and until next time, keep on learning.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
