<?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: nyaomaru</title>
    <description>The latest articles on DEV Community by nyaomaru (@nyaomaru).</description>
    <link>https://dev.to/nyaomaru</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png</url>
      <title>DEV Community: nyaomaru</title>
      <link>https://dev.to/nyaomaru</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nyaomaru"/>
    <language>en</language>
    <item>
      <title>Learn Trapping Rain Water, Top K Frequent and Selection Sort with Step-by-Step Visualization in DSA View View 👀👀</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 09 Sep 2026 12:48:25 +0000</pubDate>
      <link>https://dev.to/nyaomaru/learn-trapping-rain-water-top-k-frequent-and-selection-sort-with-step-by-step-visualization-in-dsa-1flg</link>
      <guid>https://dev.to/nyaomaru/learn-trapping-rain-water-top-k-frequent-and-selection-sort-with-step-by-step-visualization-in-dsa-1flg</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I’m &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who has been obsessed with ramen lately. 😸🍜&lt;/p&gt;

&lt;p&gt;Have you used &lt;strong&gt;DSA View View&lt;/strong&gt; already? 👀👀&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__hidden-navigation-link"&gt;I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Features a timeline to step backward mid-loop&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4143027" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 15&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" id="article-link-4143027"&gt;
          I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;64&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              33&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;DSA View View allows you to understand DSA by visualizing how your implementation actually runs.&lt;/p&gt;

&lt;p&gt;In the previous articles, we looked at problems like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two Sum&lt;/li&gt;
&lt;li&gt;Binary Search&lt;/li&gt;
&lt;li&gt;Bubble Sort&lt;/li&gt;
&lt;li&gt;Valid Parentheses&lt;/li&gt;
&lt;li&gt;Reverse Linked List&lt;/li&gt;
&lt;li&gt;Maximum Depth of Binary Tree&lt;/li&gt;
&lt;li&gt;Number of Islands&lt;/li&gt;
&lt;li&gt;Invert Binary Tree&lt;/li&gt;
&lt;li&gt;Course Schedule&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-story__hidden-navigation-link"&gt;Is Learning DSA Boring? Let's Use DSA View View 👀👀 (Two Sum, Binary Search, and Bubble Sort)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Visualizing execution logic changes mental models&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4408146" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 19&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" id="article-link-4408146"&gt;
          Is Learning DSA Boring? Let's Use DSA View View 👀👀 (Two Sum, Binary Search, and Bubble Sort)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/learning"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;learning&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;51&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              9&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;



&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09" class="crayons-story__hidden-navigation-link"&gt;Learn Valid Parentheses, Reverse Linked List, and Tree Max Depth with Step-by-Step Visualization in DSA View View 👀👀&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Curated progression from stacks to recursion&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4465798" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 26&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09" id="article-link-4465798"&gt;
          Learn Valid Parentheses, Reverse Linked List, and Tree Max Depth with Step-by-Step Visualization in DSA View View 👀👀
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/algorithms"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;algorithms&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;77&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              5&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            9 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;



&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/learn-number-of-islands-invert-binary-tree-and-course-schedule-with-step-by-step-visualization-in-5947" class="crayons-story__hidden-navigation-link"&gt;Learn Number of Islands, Invert Binary Tree, and Course Schedule with Step-by-Step Visualization in DSA View View 👀👀&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/learn-number-of-islands-invert-binary-tree-and-course-schedule-with-step-by-step-visualization-in-5947" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Readers praise the recursive swap explanation&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4521801" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/learn-number-of-islands-invert-binary-tree-and-course-schedule-with-step-by-step-visualization-in-5947" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Sep 2&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/learn-number-of-islands-invert-binary-tree-and-course-schedule-with-step-by-step-visualization-in-5947" id="article-link-4521801"&gt;
          Learn Number of Islands, Invert Binary Tree, and Course Schedule with Step-by-Step Visualization in DSA View View 👀👀
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/learn-number-of-islands-invert-binary-tree-and-course-schedule-with-step-by-step-visualization-in-5947" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;64&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/learn-number-of-islands-invert-binary-tree-and-course-schedule-with-step-by-step-visualization-in-5947#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              14&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            12 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;This time, let's try three more problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trapping Rain Water&lt;/li&gt;
&lt;li&gt;Top K Frequent Elements&lt;/li&gt;
&lt;li&gt;Selection Sort&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These three problems introduce some very useful ways of thinking&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shrink a problem from both sides
Count first, then organize by frequency
Repeatedly select the next value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once again, the implementations are not necessarily huge.&lt;/p&gt;

&lt;p&gt;But there are several changing values that we need to keep in our heads.&lt;/p&gt;

&lt;p&gt;So instead of only reading the final code,&lt;/p&gt;

&lt;p&gt;Let's view what actually happens. 👀👀&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiva15nb5rxynu3ij0kph.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiva15nb5rxynu3ij0kph.png" alt="View View Case Closed"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🌧️ Trapping Rain Water
&lt;/h2&gt;

&lt;p&gt;Let's start with &lt;strong&gt;Trapping Rain Water&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose we have these heights&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0, 1, 0, 2, 1, 0, 1, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If we draw them as walls, it looks roughly 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;              █
      █       █
  █   █ █   █ █
-----------------
0 1 0 2 1 0 1 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Rain falls from above.&lt;/p&gt;

&lt;p&gt;Some water escapes.&lt;/p&gt;

&lt;p&gt;But some water becomes trapped between taller walls.&lt;/p&gt;

&lt;p&gt;For example&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      █~~~~~~~█
  █~~~█~~~~~~~█
-----------------
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So the question is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How much water can be trapped?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first, I found this problem quite confusing. 😿&lt;/p&gt;

&lt;p&gt;Because the amount of water above one position depends on walls somewhere else.&lt;/p&gt;

&lt;p&gt;So what information do we actually need?&lt;/p&gt;
&lt;h3&gt;
  
  
  How Much Water Fits Above One Position?
&lt;/h3&gt;

&lt;p&gt;Imagine this position&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;left wall     right wall
    █             █
    █      x      █
    █      █      █
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The water level cannot be higher than the shorter side.&lt;/p&gt;

&lt;p&gt;So the maximum possible water level is&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leftMax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rightMax&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we subtract the current height.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;water = min(leftMax, rightMax) - currentHeight
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's the basic idea.&lt;/p&gt;

&lt;p&gt;But do we really need to calculate both sides again for every position?&lt;/p&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;We can use &lt;strong&gt;two pointers&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Two Pointers
&lt;/h3&gt;

&lt;p&gt;Here is the implementation.&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;function&lt;/span&gt; &lt;span class="nf"&gt;trap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;number&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;left&lt;/span&gt; &lt;span class="o"&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;let&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&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;leftMax&lt;/span&gt; &lt;span class="o"&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;let&lt;/span&gt; &lt;span class="nx"&gt;rightMax&lt;/span&gt; &lt;span class="o"&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;let&lt;/span&gt; &lt;span class="nx"&gt;water&lt;/span&gt; &lt;span class="o"&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;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&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="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&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="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;left&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;leftMax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;leftMax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;water&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;leftMax&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&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;else&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="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;right&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;rightMax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;rightMax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;water&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;rightMax&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="o"&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;return&lt;/span&gt; &lt;span class="nx"&gt;water&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;There are several important values.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;left
right
leftMax
rightMax
water
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is exactly the kind of code where I understand every variable individually,&lt;/p&gt;

&lt;p&gt;but then lose track of all of them together. 😹&lt;/p&gt;

&lt;p&gt;Let's follow a smaller example.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2, 0, 1, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Start From Both Ends
&lt;/h3&gt;

&lt;p&gt;At first&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;left = 0
right = 3

[2, 0, 1, 3]
 ↑        ↑
left    right
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The heights are:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;height[left]  = 2
height[right] = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Since&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 &amp;lt;= 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we process the left side.&lt;/p&gt;

&lt;p&gt;There is a wall with height &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;leftMax = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then move &lt;code&gt;left&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2, 0, 1, 3]
    ↑     ↑
   left right
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Now We Can Trap Water
&lt;/h3&gt;

&lt;p&gt;The current height is&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But we already know there is a wall of height &lt;code&gt;2&lt;/code&gt; on the left.&lt;/p&gt;

&lt;p&gt;And the right side is currently at least as high as that.&lt;/p&gt;

&lt;p&gt;So this position can hold&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;leftMax - height[left]
= 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Therefore&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;water = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Move again.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2, 0, 1, 3]
       ↑  ↑
      left right
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;height[left] = 1
leftMax = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 - 1 = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;One more unit of water.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;water = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Eventually we reach the final wall.&lt;/p&gt;

&lt;p&gt;Done! 🎉&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Can We Process the Shorter Side?
&lt;/h3&gt;

&lt;p&gt;This part is the important idea.&lt;/p&gt;

&lt;p&gt;Suppose&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;height[left] &amp;lt;= height[right]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we already know there is a wall on the right that is at least as tall as the current left wall.&lt;/p&gt;

&lt;p&gt;So for the current left position, the limiting factor is the best wall we have seen from the left.&lt;/p&gt;

&lt;p&gt;That's why we can safely calculate&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;leftMax&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;without knowing every future wall.&lt;/p&gt;

&lt;p&gt;The same logic works from the other side.&lt;/p&gt;

&lt;p&gt;If&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;height[right] &amp;lt; height[left]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we process the right side using &lt;code&gt;rightMax&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the algorithm keeps shrinking the unknown area&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;L → → →     ← ← ← R
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;until everything has been processed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;Each pointer only moves across the array once.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time:  O(n)
Space: O(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;This problem is a perfect example of why I like visualization.&lt;/p&gt;

&lt;p&gt;The code contains&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;left
right
leftMax
rightMax
water
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And they all change at different times.&lt;/p&gt;

&lt;p&gt;When I only read&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;water&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;leftMax&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I might ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why are we using &lt;code&gt;leftMax&lt;/code&gt; here?&lt;/li&gt;
&lt;li&gt;What is &lt;code&gt;rightMax&lt;/code&gt; right now?&lt;/li&gt;
&lt;li&gt;Why did we move &lt;code&gt;left&lt;/code&gt; instead of &lt;code&gt;right&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;How much water have we already counted?&lt;/li&gt;
&lt;li&gt;Which part of the array is still unprocessed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;😿&lt;/p&gt;

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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoidHJhcHBpbmctcmFpbi13YXRlciIsImwiOiJ0eXBlc2NyaXB0IiwibSI6InZlcmlmaWNhdGlvbiIsInYiOjF9" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Step by step, we can actually watch the search area shrink.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;L         R
↓         ↓
[2, 0, 1, 3]

    L     R
    ↓     ↓
[2, 0, 1, 3]

       L  R
       ↓  ↓
[2, 0, 1, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And at the same time&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;leftMax
rightMax
water
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;keep changing.&lt;/p&gt;

&lt;p&gt;The algorithm is really asking&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which side can I safely solve right now?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then it solves that side and moves inward. 🌧️😸&lt;/p&gt;


&lt;h2&gt;
  
  
  🔢 Top K Frequent Elements
&lt;/h2&gt;

&lt;p&gt;Next, let's find the &lt;strong&gt;Top K Frequent Elements&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose we have&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 1, 1, 2, 2, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;k = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;How often does each number appear?&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 3 times
2 → 2 times
3 → 1 time
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So the two most frequent values are&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Simple enough.&lt;/p&gt;

&lt;p&gt;But how should we implement it?&lt;/p&gt;
&lt;h3&gt;
  
  
  First, Count Everything
&lt;/h3&gt;

&lt;p&gt;The first thing we need is frequency.&lt;/p&gt;

&lt;p&gt;We can use a &lt;code&gt;Map&lt;/code&gt;.&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;frequency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&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="p"&gt;,&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then count each value.&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;for &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;num&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;frequency&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;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;For&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 1, 1, 2, 2, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we get&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frequency = {
  1 → 3
  2 → 2
  3 → 1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Nice.&lt;/p&gt;

&lt;p&gt;But we still need the &lt;strong&gt;top K&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Of course, we could sort everything by frequency.&lt;/p&gt;

&lt;p&gt;But there is another interesting approach.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use Frequency as an Index
&lt;/h3&gt;

&lt;p&gt;The maximum possible frequency is&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nums.length
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So we can create buckets.&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;buckets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[][]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&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="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The index represents frequency.&lt;/p&gt;

&lt;p&gt;For example&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bucket[1] = values appearing 1 time
bucket[2] = values appearing 2 times
bucket[3] = values appearing 3 times
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For our example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frequency = {
  1 → 3
  2 → 2
  3 → 1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;the buckets become&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index 0 → []
index 1 → [3]
index 2 → [2]
index 3 → [1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's pretty interesting. 👀👀&lt;/p&gt;

&lt;p&gt;Instead of asking&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is the frequency of this number?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;we reverse the relationship&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which numbers have this frequency?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;Here is the full implementation:&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;function&lt;/span&gt; &lt;span class="nf"&gt;topKFrequent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&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;frequency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&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="p"&gt;,&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="k"&gt;for &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;num&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;frequency&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;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;buckets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[][]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&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="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&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;for &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;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;for &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;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&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;for &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;num&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;k&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;result&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;return&lt;/span&gt; &lt;span class="nx"&gt;result&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;Let's follow it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Build the Frequency Map
&lt;/h3&gt;

&lt;p&gt;Start&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frequency = {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Read the first &lt;code&gt;1&lt;/code&gt;. And another one and another...&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 1
1 → 2
1 → 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then &lt;code&gt;2&lt;/code&gt;. And another one.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 3
2 → 1
2 → 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally &lt;code&gt;3&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 3
2 → 2
3 → 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Done.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Put Values Into Buckets
&lt;/h3&gt;

&lt;p&gt;Now&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;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we do&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;buckets[3].push(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 → 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we do&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;buckets[2].push(2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3 → 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;becomes&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;buckets[1].push(3)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0: []
1: [3]
2: [2]
3: [1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 3: Read From Highest Frequency
&lt;/h3&gt;

&lt;p&gt;We want the &lt;strong&gt;most frequent&lt;/strong&gt; values.&lt;/p&gt;

&lt;p&gt;So don't start at &lt;code&gt;0&lt;/code&gt;. Start from the end.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3 → [1]
2 → [2]
1 → [3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Take &lt;code&gt;1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;result = [1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We still need one more. Move down.&lt;/p&gt;

&lt;p&gt;Take &lt;code&gt;2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;result = [1, 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;result.length === k
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So return.&lt;/p&gt;

&lt;p&gt;Done! 🎉&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Is This Interesting?
&lt;/h3&gt;

&lt;p&gt;I like this solution because the second structure changes our perspective.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Map&lt;/code&gt; says&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;value → frequency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The buckets say&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frequency → values
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Same information. But different direction.&lt;/p&gt;

&lt;p&gt;And suddenly finding the most frequent values becomes easy.&lt;/p&gt;

&lt;p&gt;We just walk backward through the buckets.&lt;/p&gt;
&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;We count every number once.&lt;/p&gt;

&lt;p&gt;We distribute every unique number into a bucket.&lt;/p&gt;

&lt;p&gt;Then we walk through the buckets.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time:  O(n)
Space: O(n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;There are two transformations happening here.&lt;/p&gt;

&lt;p&gt;First&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nums
 ↓
frequency Map
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frequency Map
 ↓
buckets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;buckets
 ↓
result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Reading the final implementation, it can be easy to miss why we're building two different data structures.&lt;/p&gt;

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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoidG9wLWstZnJlcXVlbnQiLCJsIjoidHlwZXNjcmlwdCIsIm0iOiJ2ZXJpZmljYXRpb24iLCJ2IjoxfQ" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;With the runtime visible, we can follow the data changing shape.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 1, 1, 2, 2, 3]
        ↓ count
1 → 3
2 → 2
3 → 1
        ↓ bucket
1: [3]
2: [2]
3: [1]
        ↓ highest first
[1, 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's the part I like.&lt;/p&gt;

&lt;p&gt;We don't magically find the top K.&lt;/p&gt;

&lt;p&gt;We reorganize the information until the answer becomes easy to read. 🔢😸&lt;/p&gt;


&lt;h2&gt;
  
  
  👉 Selection Sort
&lt;/h2&gt;

&lt;p&gt;Finally, let's sort something again!&lt;/p&gt;

&lt;p&gt;We already looked at &lt;strong&gt;Bubble Sort&lt;/strong&gt; in a previous article.&lt;/p&gt;

&lt;p&gt;This time, let's try &lt;strong&gt;Selection Sort&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose we have&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[5, 3, 4, 1, 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We want&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Selection Sort follows a very simple idea&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find the smallest remaining value and move it to the front.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then repeat.&lt;/p&gt;
&lt;h3&gt;
  
  
  First Pass
&lt;/h3&gt;

&lt;p&gt;Start&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[5, 3, 4, 1, 2]
 ↑
 i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Assume the first value is currently the smallest.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minIndex = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then scan everything to the right.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5 vs 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;3&lt;/code&gt; is smaller.&lt;/p&gt;

&lt;p&gt;So:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minIndex = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3 vs 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;No change.&lt;/p&gt;

&lt;p&gt;Then&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3 vs 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;1&lt;/code&gt; is smaller.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minIndex = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 vs 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Still &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the smallest value is at index &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Swap&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[5, 3, 4, 1, 2]
 ↑        ↑
 i       min
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;↓&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 3, 4, 5, 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now the first position is finished.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1 | 3, 4, 5, 2]
 ↑
sorted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Repeat
&lt;/h3&gt;

&lt;p&gt;Next, start from index &lt;code&gt;1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1 | 3, 4, 5, 2]
     ↑
     i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Find the smallest value in&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[3, 4, 5, 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Swap.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2 | 4, 5, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Again.&lt;/p&gt;

&lt;p&gt;Find the smallest remaining value.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Eventually&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Sorted! 🎉&lt;/p&gt;
&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;selectionSort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;let&lt;/span&gt; &lt;span class="nx"&gt;minIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for &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;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;minIndex&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;minIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;j&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minIndex&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;minIndex&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;minIndex&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;return&lt;/span&gt; &lt;span class="nx"&gt;nums&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;There are two important indexes.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i
minIndex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And also&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;j
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;which searches through the unsorted area.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Is It Called Selection Sort?
&lt;/h3&gt;

&lt;p&gt;Because each pass &lt;strong&gt;selects&lt;/strong&gt; the smallest remaining value.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find smallest
  ↓
Select it
  ↓
Move it to the front
  ↓
Repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's basically the whole algorithm.&lt;/p&gt;
&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;For every position, we search through the remaining values.&lt;/p&gt;

&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time: O(n²)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We sort the array in place.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Space: O(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Selection Sort is not something I would normally choose for sorting a huge production dataset. 😹&lt;/p&gt;

&lt;p&gt;But as a learning algorithm, it is wonderfully visual.&lt;/p&gt;
&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;The implementation contains nested loops.&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;for &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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;let&lt;/span&gt; &lt;span class="nx"&gt;minIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for &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;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&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;Reading it, I might lose track of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which area is already sorted?&lt;/li&gt;
&lt;li&gt;Where is &lt;code&gt;i&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Where is &lt;code&gt;j&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;What does &lt;code&gt;minIndex&lt;/code&gt; currently point to?&lt;/li&gt;
&lt;li&gt;When exactly does the swap happen?&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/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkdp1snvp20a2re0dgkt9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkdp1snvp20a2re0dgkt9.gif" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoic2VsZWN0aW9uLXNvcnQiLCJsIjoidHlwZXNjcmlwdCIsIm0iOiJ2ZXJpZmljYXRpb24iLCJ2IjoxfQ" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;When we visualize it, the basic pattern becomes obvious.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[5, 3, 4, 1, 2]
          ↑
       smallest

[1 | 3, 4, 5, 2]
              ↑
           smallest

[1, 2 | 4, 5, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The algorithm is continuously growing a finished area from left to right.&lt;/p&gt;

&lt;p&gt;That's Selection Sort.&lt;/p&gt;

&lt;p&gt;Pick the smallest remaining value.&lt;/p&gt;

&lt;p&gt;Put it next. And repeat. 🍥😸&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 What Did We Actually Learn?
&lt;/h2&gt;

&lt;p&gt;Again, these three problems look completely different.&lt;/p&gt;

&lt;p&gt;But each one introduces a useful way of thinking.&lt;/p&gt;
&lt;h3&gt;
  
  
  Trapping Rain Water
&lt;/h3&gt;

&lt;p&gt;Use information from both sides to decide which part can already be solved safely.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which side do I know enough about right now?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Top K Frequent Elements
&lt;/h3&gt;

&lt;p&gt;Sometimes counting the data is only the first step.&lt;/p&gt;

&lt;p&gt;Reorganize it into a structure where the answer becomes easy to retrieve.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can I reorganize this information around what I actually need?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Selection Sort
&lt;/h3&gt;

&lt;p&gt;Build the answer one permanent position at a time.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What value belongs in this position next?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So this time we saw&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Two pointers
Frequency buckets
Selection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Three different mental models again.&lt;/p&gt;

&lt;p&gt;And just like the previous problems, the difficult part is often not the syntax.&lt;/p&gt;

&lt;p&gt;It's the changing state.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which pointer moved?
What is the maximum now?
What is inside the Map?
Which bucket changed?
Where is minIndex?
Which part is already finished?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's a lot to keep in our heads.&lt;/p&gt;

&lt;p&gt;So instead, I want to &lt;strong&gt;view it&lt;/strong&gt;. 👀👀&lt;/p&gt;


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

&lt;p&gt;In this article, we looked at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trapping Rain Water with two pointers&lt;/li&gt;
&lt;li&gt;Top K Frequent Elements with frequency buckets&lt;/li&gt;
&lt;li&gt;Selection Sort&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And more importantly, we followed how their state changes while they run.&lt;/p&gt;

&lt;p&gt;For Trapping Rain Water, we watched two pointers move inward while &lt;code&gt;leftMax&lt;/code&gt;, &lt;code&gt;rightMax&lt;/code&gt;, and &lt;code&gt;water&lt;/code&gt; changed.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;left →       ← right
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For Top K Frequent Elements, we watched the same data change representation.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;array
  ↓
frequency Map
  ↓
buckets
  ↓
result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For Selection Sort, we watched the sorted area grow one position at a time.&lt;/p&gt;

&lt;p&gt;This is exactly the kind of thing I built &lt;strong&gt;DSA View View&lt;/strong&gt; for.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You can write or load a TypeScript implementation, run it with your own inputs, and move backward and forward through the runtime.&lt;/p&gt;

&lt;p&gt;If you are learning DSA too, try viewing one of these problems step by step.&lt;/p&gt;

&lt;p&gt;And if there is a DSA problem you want me to cover next, please let me know in the comments!&lt;/p&gt;

&lt;p&gt;I still have many algorithms to learn myself. 😸&lt;/p&gt;

&lt;p&gt;Let's train our DSA muscles together! 💪&lt;/p&gt;

&lt;p&gt;If you like DSA View View, please give it a star ⭐&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;
        dsa-view-view
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DSA View View allows you to understand DSA to see the data flow. 👀👀 Of course, it's free.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nyaomaru/dsa-view-view/./public/readme-view-view.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Freadme-view-view.png" alt="DSA View View" width="100%"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DSA View View&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;DSA View View turns TypeScript algorithm functions into step-by-step visual
stories. 👀👀&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-tv.gif" alt="DSA View View TV"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Write code, run it with structured inputs, and see the arrays, matrices
trees, lists, stacks, pointers, and return values move as the function executes.&lt;/p&gt;
&lt;p&gt;It is built for those moments when reading the code is not enough and you want
to &lt;em&gt;view&lt;/em&gt; why the answer changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-demo.gif" alt="DSA View View demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Try It?&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🧠 &lt;strong&gt;Step through real TypeScript&lt;/strong&gt;&lt;br&gt;
Paste or edit a function, validate it, then run the exact code in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🧩 &lt;strong&gt;Views that match the data&lt;/strong&gt;&lt;br&gt;
Arrays become bars, matrices become grids, trees become node graphs, linked lists become chains, and two-pointer area problems get their own visual view.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🌳 &lt;strong&gt;DSA-friendly inputs out of the box&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;TreeNode&lt;/code&gt;, &lt;code&gt;ListNode&lt;/code&gt;, &lt;code&gt;MinHeap&lt;/code&gt;, &lt;code&gt;MaxHeap&lt;/code&gt;, &lt;code&gt;PriorityQueue&lt;/code&gt;, nested arrays
matrices, strings, numbers, and class-style inputs are supported without
ceremony.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔎 &lt;strong&gt;39 built-in examples&lt;/strong&gt;&lt;br&gt;
Search by name, browse…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;See you in the next article!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>opensource</category>
      <category>dsa</category>
    </item>
    <item>
      <title>Learn Number of Islands, Invert Binary Tree, and Course Schedule with Step-by-Step Visualization in DSA View View 👀👀</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 02 Sep 2026 14:54:12 +0000</pubDate>
      <link>https://dev.to/nyaomaru/learn-number-of-islands-invert-binary-tree-and-course-schedule-with-step-by-step-visualization-in-5947</link>
      <guid>https://dev.to/nyaomaru/learn-number-of-islands-invert-binary-tree-and-course-schedule-with-step-by-step-visualization-in-5947</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I’m &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who is surprised by how cold it is in the Netherlands even though it’s still summer. 😸&lt;/p&gt;

&lt;p&gt;Have you used &lt;strong&gt;DSA View View&lt;/strong&gt; already? 👀👀&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__hidden-navigation-link"&gt;I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Features a timeline to step backward mid-loop&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4143027" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 15&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" id="article-link-4143027"&gt;
          I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;64&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              33&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;DSA View View allows you to understand DSA by visualizing how your implementation actually runs.&lt;/p&gt;

&lt;p&gt;In the previous articles, we looked at problems like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two Sum&lt;/li&gt;
&lt;li&gt;Binary Search&lt;/li&gt;
&lt;li&gt;Bubble Sort&lt;/li&gt;
&lt;li&gt;Valid Parentheses&lt;/li&gt;
&lt;li&gt;Reverse Linked List&lt;/li&gt;
&lt;li&gt;Maximum Depth of Binary Tree&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-story__hidden-navigation-link"&gt;Is Learning DSA Boring? Let's Use DSA View View 👀👀 (Two Sum, Binary Search, and Bubble Sort)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Visualizing execution logic changes mental models&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4408146" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 19&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" id="article-link-4408146"&gt;
          Is Learning DSA Boring? Let's Use DSA View View 👀👀 (Two Sum, Binary Search, and Bubble Sort)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/learning"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;learning&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;51&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              9&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;



&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09" class="crayons-story__hidden-navigation-link"&gt;Learn Valid Parentheses, Reverse Linked List, and Tree Max Depth with Step-by-Step Visualization in DSA View View 👀👀&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Curated progression from stacks to recursion&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4465798" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 26&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09" id="article-link-4465798"&gt;
          Learn Valid Parentheses, Reverse Linked List, and Tree Max Depth with Step-by-Step Visualization in DSA View View 👀👀
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/algorithms"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;algorithms&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;77&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              5&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            9 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;This time, let's try three more classic problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Number of Islands&lt;/li&gt;
&lt;li&gt;Invert Binary Tree&lt;/li&gt;
&lt;li&gt;Course Schedule&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These three problems introduce some very useful ways of thinking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Explore connected things
Transform a tree with recursion
Resolve dependencies in the right order
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The implementations are not huge.&lt;/p&gt;

&lt;p&gt;But the runtime can become surprisingly difficult to hold in our heads.&lt;/p&gt;

&lt;p&gt;So let's view what actually happens. 👀&lt;/p&gt;

&lt;p&gt;Let's learn together! 😸&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F67vo0y715kpacm6823nm.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F67vo0y715kpacm6823nm.png" alt="Step view 3"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🏝️ Number of Islands
&lt;/h2&gt;

&lt;p&gt;Let's start with &lt;strong&gt;Number of Islands&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose we have this grid:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 1 0 0
1 0 0 1
0 0 1 1
0 0 0 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;1&lt;/code&gt; means land. 🏝️&lt;/p&gt;

&lt;p&gt;&lt;code&gt;0&lt;/code&gt; means water. 🌊&lt;/p&gt;

&lt;p&gt;Land connected vertically or horizontally belongs to the same island.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So how many islands are there?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's look at the first group.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 1
1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These cells are connected.&lt;/p&gt;

&lt;p&gt;So they form &lt;strong&gt;one island&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On the right side&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    1
  1 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Those cells are also connected.&lt;/p&gt;

&lt;p&gt;So the answer is &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nice! 🏝️🏝️&lt;/p&gt;

&lt;p&gt;But how do we make the code understand that several &lt;code&gt;1&lt;/code&gt;s belong to the same island?&lt;/p&gt;
&lt;h3&gt;
  
  
  Find One Land, Then Explore All Connected Land
&lt;/h3&gt;

&lt;p&gt;The basic idea is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When we find a new &lt;code&gt;1&lt;/code&gt;, count one island and visit all land connected to it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's use this implementation.&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;function&lt;/span&gt; &lt;span class="nf"&gt;numIslands&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;grid&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="kr"&gt;number&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;islands&lt;/span&gt; &lt;span class="o"&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;visit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&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="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;return&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="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&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="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;for &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;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="o"&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;for &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;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&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;islands&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&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;return&lt;/span&gt; &lt;span class="nx"&gt;islands&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;There are two important parts.&lt;/p&gt;

&lt;p&gt;First, we scan the grid&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;for &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;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="o"&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;for &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;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="o"&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;Then, when we find land&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="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&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;islands&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&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;We count a new island.&lt;/p&gt;

&lt;p&gt;But then &lt;code&gt;visit()&lt;/code&gt; does something important.&lt;/p&gt;

&lt;p&gt;It removes all land connected to that island from future consideration.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Do We Change &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Inside &lt;code&gt;visit()&lt;/code&gt; we have&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;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At first, changing land into water looks a little strange. 😿&lt;/p&gt;

&lt;p&gt;But here, &lt;code&gt;0&lt;/code&gt; really means&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We already visited this land.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's follow a tiny example.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 1
1 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We start at the top-left. And we found land! So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;islands = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then&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;visit&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Inside &lt;code&gt;visit()&lt;/code&gt;, we mark it as visited.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 1
1 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we visit the four directions&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;down
up
right
left
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Going down finds another &lt;code&gt;1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 1
1 0
↑
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So we visit it too.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 1
0 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Going right from the original cell also finds land.&lt;/p&gt;

&lt;p&gt;Visit it.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 0
0 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now the whole connected island has disappeared from our search.&lt;/p&gt;

&lt;p&gt;When the outer loops continue, there is no &lt;code&gt;1&lt;/code&gt; left in that island to count again.&lt;/p&gt;

&lt;p&gt;That's the key idea.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Count once, then mark the whole connected area as visited.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Why Four Recursive Calls?
&lt;/h3&gt;

&lt;p&gt;We 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="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&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;That means&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        up
         ↑
left ← current → right
         ↓
        down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each visited cell asks&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is there more land next to me?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And every newly discovered land cell asks the same question again.&lt;/p&gt;

&lt;p&gt;This continues until we reach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;water&lt;/li&gt;
&lt;li&gt;outside the grid&lt;/li&gt;
&lt;li&gt;land we already visited&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those cases stop the recursion.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Base Cases
&lt;/h3&gt;

&lt;p&gt;These lines protect us&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="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;return&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="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&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="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If we walk outside the grid, stop.&lt;/li&gt;
&lt;li&gt;If we reach water, stop.&lt;/li&gt;
&lt;li&gt;If we reach a cell we already changed to &lt;code&gt;0&lt;/code&gt;, stop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Otherwise, continue exploring.&lt;/p&gt;
&lt;h3&gt;
  
  
  Let's Follow Two Islands
&lt;/h3&gt;

&lt;p&gt;Consider&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 1 0
0 0 1
0 1 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The scan begins at the top-left.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 1 0
↑
0 0 1
0 1 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Found land.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;islands = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;visit()&lt;/code&gt; removes everything connected to it.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 0 0
0 0 1
0 1 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The loops continue.&lt;/p&gt;

&lt;p&gt;Eventually we reach&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 0 0
0 0 1
    ↑
0 1 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Another &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;islands = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And &lt;code&gt;visit()&lt;/code&gt; explores that entire connected area.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 0 0
0 0 0
0 0 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Done!&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 islands
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;🎉&lt;/p&gt;
&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;Every cell is processed at most a small number of times.&lt;/p&gt;

&lt;p&gt;If the grid has &lt;code&gt;m&lt;/code&gt; rows and &lt;code&gt;n&lt;/code&gt; columns&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time:  O(m × n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the worst case, the recursive call stack may grow with the number of land cells.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Space: O(m × n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;This is one of those algorithms where the final code is pretty small.&lt;/p&gt;

&lt;p&gt;But while reading it, there are a lot of things moving at once&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;row
col
grid
islands
recursive calls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And then suddenly we see&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;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Why did that cell disappear?&lt;/li&gt;
&lt;li&gt;Which recursive call are we inside?&lt;/li&gt;
&lt;li&gt;Which cells belong to the current island?&lt;/li&gt;
&lt;li&gt;Where will the outer loop continue after recursion finishes?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a lot to simulate mentally. 😿&lt;/p&gt;

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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoibnVtYmVyLW9mLWlzbGFuZHMiLCJsIjoidHlwZXNjcmlwdCIsIm0iOiJ2ZXJpZmljYXRpb24iLCJ2IjoxfQ" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;When we view it step by step, the idea becomes much more visual.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find land
  ↓
islands++
  ↓
visit connected land
  ↓
mark it visited
  ↓
expand up / down / left / right
  ↓
return to scanning
  ↓
find next island
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Instead of thinking about recursion first, I like to think about it like this&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find one island, paint the whole island away, then keep searching.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🏝️😸&lt;/p&gt;


&lt;h2&gt;
  
  
  🌳 Invert Binary Tree
&lt;/h2&gt;

&lt;p&gt;Next, let's invert a binary tree.&lt;/p&gt;

&lt;p&gt;Suppose we have&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        4
       / \
      2   7
     / \ / \
    1  3 6  9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We want to change&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        4
       / \
      7   2
     / \ / \
    9  6 3  1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Every left child becomes the right child.&lt;/p&gt;

&lt;p&gt;Every right child becomes the left child.&lt;/p&gt;

&lt;p&gt;Simple, right?&lt;/p&gt;

&lt;p&gt;Well, the final implementation is also surprisingly small.&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;function&lt;/span&gt; &lt;span class="nf"&gt;invertTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TreeNode&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TreeNode&lt;/span&gt; &lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&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;return&lt;/span&gt; &lt;span class="kc"&gt;null&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;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;invertTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&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;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;invertTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;left&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;root&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;That's almost suspiciously short. 👀&lt;/p&gt;
&lt;h3&gt;
  
  
  Go Down First
&lt;/h3&gt;

&lt;p&gt;Let's use a smaller tree.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    1
   / \
  2   3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We start at node &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But we don't swap immediately.&lt;/p&gt;

&lt;p&gt;First,&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;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;invertTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So we go to node &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Node &lt;code&gt;2&lt;/code&gt; also tries to invert its left child.&lt;/p&gt;

&lt;p&gt;But there is no child.&lt;/p&gt;

&lt;p&gt;So&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="nx"&gt;root&lt;/span&gt; &lt;span class="o"&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;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;returns &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The same thing happens on the right side of node &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now node &lt;code&gt;2&lt;/code&gt; has&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;left = null
right = null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&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;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;does not visibly change anything.&lt;/p&gt;

&lt;p&gt;Node &lt;code&gt;2&lt;/code&gt; returns.&lt;/p&gt;

&lt;p&gt;Then node &lt;code&gt;1&lt;/code&gt; explores its right subtree.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Node &lt;code&gt;3&lt;/code&gt; also has no children, so it returns after the same process.&lt;/p&gt;

&lt;p&gt;Only then do we come back to node &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;left = 2
right = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And we do&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;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    1
   / \
  2   3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;becomes 👇&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    1
   / \
  3   2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Done! 🎉&lt;/p&gt;
&lt;h3&gt;
  
  
  The Important Part: The Swap Happens on the Way Back
&lt;/h3&gt;

&lt;p&gt;This is what makes the recursive solution interesting.&lt;/p&gt;

&lt;p&gt;The function first goes down.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
↓
2
↓
null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then it comes back.&lt;/p&gt;

&lt;p&gt;Later it explores the other side.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
↓
3
↓
null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And after both children have returned, the current node swaps them.&lt;/p&gt;

&lt;p&gt;So the flow is more like&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Go left
  ↓
Invert left subtree
  ↓
Go right
  ↓
Invert right subtree
  ↓
Swap the returned subtrees
  ↓
Return current node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The tree transformation is built while recursion unwinds.&lt;/p&gt;
&lt;h3&gt;
  
  
  A Slightly Bigger Example
&lt;/h3&gt;

&lt;p&gt;Let's look at&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      4
     / \
    2   7
   / \
  1   3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We start at &lt;code&gt;4&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;invertTree(4)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;invertTree(2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;invertTree(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Node &lt;code&gt;1&lt;/code&gt; returns.&lt;/p&gt;

&lt;p&gt;Then node &lt;code&gt;3&lt;/code&gt; returns.&lt;/p&gt;

&lt;p&gt;Now node &lt;code&gt;2&lt;/code&gt; has&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;left = 1
right = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Swap them.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    2
   / \
  3   1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then recursion returns to &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The right subtree rooted at &lt;code&gt;7&lt;/code&gt; is also processed.&lt;/p&gt;

&lt;p&gt;Finally node &lt;code&gt;4&lt;/code&gt; receives&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;left = inverted subtree rooted at 2
right = inverted subtree rooted at 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and swaps them.&lt;/p&gt;

&lt;p&gt;The final tree becomes&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      4
     / \
    7   2
       / \
      3   1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The interesting thing is that each node only needs to know about its own two children.&lt;/p&gt;

&lt;p&gt;It doesn't need to understand the whole tree.&lt;/p&gt;
&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;We visit every node once.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time: O(n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The recursive call stack depends on the height of the tree.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Space: O(h)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For a balanced tree&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;O(log n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the worst case&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;O(n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;This is exactly where recursion can become difficult to mentally simulate.&lt;/p&gt;

&lt;p&gt;The code says&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;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;invertTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&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;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;invertTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then&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;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But my brain immediately starts asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which root are we talking about now?&lt;/li&gt;
&lt;li&gt;Did node 2 already swap?&lt;/li&gt;
&lt;li&gt;Are we still going down?&lt;/li&gt;
&lt;li&gt;Or are we coming back up?&lt;/li&gt;
&lt;li&gt;What does left contain at this moment?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;😿&lt;/p&gt;

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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoiaW52ZXJ0LWJpbmFyeS10cmVlIiwibCI6InR5cGVzY3JpcHQiLCJtIjoidmVyaWZpY2F0aW9uIiwidiI6MX0" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;When we step through the runtime, we can separate two different movements.&lt;/p&gt;

&lt;p&gt;The final code is short.&lt;/p&gt;

&lt;p&gt;But the actual runtime has a rhythm 🎵&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Go down
↓
Return
↓
Swap
↓
Return
↓
Swap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once I can see that rhythm, the recursive solution feels much less magical. 🌳😸&lt;/p&gt;


&lt;h2&gt;
  
  
  🎓 Course Schedule
&lt;/h2&gt;

&lt;p&gt;Finally, let's look at &lt;strong&gt;Course Schedule&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This one is a little more difficult.&lt;/p&gt;

&lt;p&gt;Suppose we have three courses&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0
1
2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And the prerequisites are&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 0]
[2, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That means&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;To take course 1, finish course 0 first.
To take course 2, finish course 1 first.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So the dependency looks like&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 → 1 → 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Can we finish all courses?&lt;/p&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;We can take them in this order &lt;code&gt;0 → 1 → 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Easy.&lt;/p&gt;

&lt;p&gt;But what if the dependencies look 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;0 → 1
↑   ↓
└── 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 needs 2
1 needs 0
2 needs 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Everyone is waiting for someone else.&lt;/p&gt;

&lt;p&gt;We can never start.&lt;/p&gt;

&lt;p&gt;That is a &lt;strong&gt;cycle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And if there is a cycle, we cannot finish all courses.&lt;/p&gt;
&lt;h3&gt;
  
  
  Build the Graph
&lt;/h3&gt;

&lt;p&gt;Here is the implementation:&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;function&lt;/span&gt; &lt;span class="nf"&gt;canFinish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numCourses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prerequisites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[][]):&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[][]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&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="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;numCourses&lt;/span&gt; &lt;span class="p"&gt;},&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;indegree&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numCourses&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&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;for &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;course&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prerequisite&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;prerequisites&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prerequisite&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;indegree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&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;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;for &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;course&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;course&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;numCourses&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;indegree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="p"&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;completed&lt;/span&gt; &lt;span class="o"&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;for &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;head&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;head&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&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;course&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for &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;next&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;indegree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&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="nx"&gt;indegree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&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;return&lt;/span&gt; &lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;numCourses&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;There are a few moving parts here.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph
indegree
queue
completed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is exactly the kind of algorithm where every individual line makes sense.&lt;/p&gt;

&lt;p&gt;but the whole thing can still feel confusing. 😿&lt;/p&gt;

&lt;p&gt;Let's break it down.&lt;/p&gt;
&lt;h3&gt;
  
  
  What Is &lt;code&gt;graph&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;For&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 → 1 → 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we want to know&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After I finish this course, which courses become closer to being available?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph[0] = [1]
graph[1] = [2]
graph[2] = []
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That means&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Finish 0
↓
course 1 is affected

Finish 1
↓
course 2 is affected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We build that here&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;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prerequisite&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  What Is &lt;code&gt;indegree&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;indegree&lt;/code&gt; tells us how many prerequisites a course is still waiting for.&lt;/p&gt;

&lt;p&gt;For&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 → 1 → 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we have&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;course 0: 0 prerequisites
course 1: 1 prerequisite
course 2: 1 prerequisite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;indegree = [0, 1, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Course &lt;code&gt;0&lt;/code&gt; is special. Because it does not need anything before it.&lt;/p&gt;

&lt;p&gt;So we can start there immediately.&lt;/p&gt;
&lt;h3&gt;
  
  
  Start With Courses That Need Nothing
&lt;/h3&gt;

&lt;p&gt;We build the queue&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;for &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;course&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;course&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;numCourses&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;indegree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;course&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;For our example&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;indegree = [0, 1, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Only course &lt;code&gt;0&lt;/code&gt; has zero prerequisites.&lt;/p&gt;

&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queue = [0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This means&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Course 0 is currently available.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Finish Course 0
&lt;/h3&gt;

&lt;p&gt;Take&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;course = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then&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;completed&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;completed = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now look at courses depending on &lt;code&gt;0&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph[0] = [1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Course &lt;code&gt;1&lt;/code&gt; was waiting for one prerequisite.&lt;/p&gt;

&lt;p&gt;But course &lt;code&gt;0&lt;/code&gt; is now complete.&lt;/p&gt;

&lt;p&gt;So&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;indegree&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;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;indegree[1] = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now course &lt;code&gt;1&lt;/code&gt; needs nothing.&lt;/p&gt;

&lt;p&gt;So we add it to the queue.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queue = [0, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Finish Course 1
&lt;/h3&gt;

&lt;p&gt;Next&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;course = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;completed = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Course &lt;code&gt;2&lt;/code&gt; depends on &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;indegree[2]: 1 → 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Add it to the queue.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queue = [0, 1, 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Finish Course 2
&lt;/h3&gt;

&lt;p&gt;Finally&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;course = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;completed = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;numCourses = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Therefore&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;completed&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;numCourses&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can finish everything! 🎉&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Does This Detect a Cycle?
&lt;/h3&gt;

&lt;p&gt;Now let's try&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 → 1
↑   ↓
└── 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Every course has one prerequisite.&lt;/p&gt;

&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;indegree = [1, 1, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We try to build the initial queue.&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="nx"&gt;indegree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But there is no course with indegree &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, nothing can start.&lt;/p&gt;

&lt;p&gt;Therefore&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;completed = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 === 3 // false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We cannot finish the courses.&lt;/p&gt;
&lt;h3&gt;
  
  
  Another Example
&lt;/h3&gt;

&lt;p&gt;Suppose&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 → 2
1 → 2
2 → 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Course &lt;code&gt;2&lt;/code&gt; needs both &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;indegree = [0, 0, 2, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The initial queue is&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queue = [0, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finish &lt;code&gt;0&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;indegree[2]: 2 → 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Course &lt;code&gt;2&lt;/code&gt; is still waiting.&lt;/p&gt;

&lt;p&gt;So don't add it yet.&lt;/p&gt;

&lt;p&gt;Finish &lt;code&gt;1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;indegree[2]: 1 → 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now course &lt;code&gt;2&lt;/code&gt; is ready.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queue = [0, 1, 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finish &lt;code&gt;2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;indegree[3]: 1 → 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queue = [0, 1, 2, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Everything can be completed.&lt;/p&gt;

&lt;p&gt;This is the key idea&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When all prerequisites for a course are resolved, that course becomes available.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Why Use &lt;code&gt;head&lt;/code&gt; Instead of &lt;code&gt;shift()&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;The queue is processed 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="k"&gt;for &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;head&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;head&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&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;course&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Instead of repeatedly doing&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;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we keep an index pointing to the next item to process.&lt;/p&gt;

&lt;p&gt;So the queue can grow while we iterate through it.&lt;/p&gt;

&lt;p&gt;For example&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queue = [0]

process 0
↓
queue = [0, 1]

process 1
↓
queue = [0, 1, 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;head&lt;/code&gt; simply moves forward.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 → 1 → 2
↑
head
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 → 1 → 2
    ↑
   head
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 → 1 → 2
        ↑
       head
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;V = number of courses
E = number of prerequisite relationships
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We build the graph once and process every course and edge.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time: O(V + E)
Space: O(V + E)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;This is probably the most interesting visualization of the three.&lt;/p&gt;

&lt;p&gt;Because there are several things changing together.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph
indegree
queue
head
completed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If I only read&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;indegree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&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="nx"&gt;indegree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I understand the syntax.&lt;/p&gt;

&lt;p&gt;But I may still ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why did this course become available now?&lt;/li&gt;
&lt;li&gt;Which prerequisite was removed?&lt;/li&gt;
&lt;li&gt;Why is this course still not in the queue?&lt;/li&gt;
&lt;li&gt;What does completed tell us?&lt;/li&gt;
&lt;li&gt;Where exactly does the cycle get stuck?&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/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzex8dki7lbeafw64xz2x.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzex8dki7lbeafw64xz2x.gif" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoiY291cnNlLXNjaGVkdWxlIiwibCI6InR5cGVzY3JpcHQiLCJtIjoidmVyaWZpY2F0aW9uIiwidiI6MX0" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;When we view the runtime, we can watch the dependencies disappear.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 → 1 → 2

indegree = [0, 1, 1]
queue = [0]

       ↓ finish 0

indegree = [0, 0, 1]
queue = [0, 1]

       ↓ finish 1

indegree = [0, 0, 0]
queue = [0, 1, 2]

       ↓ finish 2

completed = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The code stops feeling like mysterious bookkeeping.&lt;/p&gt;

&lt;p&gt;We're really doing one simple thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep taking courses that are ready, and make their dependent courses closer to being ready.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If eventually every course becomes ready&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;completed === numCourses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;there is no blocking cycle.&lt;/p&gt;

&lt;p&gt;If some courses never become ready&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;completed &amp;lt; numCourses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;something is stuck in a cycle. 🎓😸&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 What Did We Actually Learn?
&lt;/h2&gt;

&lt;p&gt;These three problems look very different.&lt;/p&gt;

&lt;p&gt;But each one teaches a useful way of thinking.&lt;/p&gt;
&lt;h3&gt;
  
  
  Number of Islands
&lt;/h3&gt;

&lt;p&gt;When you find one part of a connected group, explore the entire group before continuing.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What else is connected to this?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Invert Binary Tree
&lt;/h3&gt;

&lt;p&gt;Let recursive calls solve the smaller subtrees first, then transform the current node using their results.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can my children finish their work before I change this node?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Course Schedule
&lt;/h3&gt;

&lt;p&gt;Process things that have no unresolved dependencies, then use them to unlock more work.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What can I safely process right now?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The implementations are not very long.&lt;/p&gt;

&lt;p&gt;But each one introduces a different mental model.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DFS on a grid
Recursive tree transformation
Topological sorting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And once again, the syntax is not really the hardest part.&lt;/p&gt;

&lt;p&gt;The difficult part is keeping track of the changing state.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where are we?&lt;/li&gt;
&lt;li&gt;What changed?&lt;/li&gt;
&lt;li&gt;What is waiting?&lt;/li&gt;
&lt;li&gt;What has already been visited?&lt;/li&gt;
&lt;li&gt;Which recursive call are we inside?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes I can read every line and still lose the thread somewhere in the middle. 😿&lt;/p&gt;

&lt;p&gt;That's exactly when I want to &lt;strong&gt;view it&lt;/strong&gt;. 👀👀&lt;/p&gt;


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

&lt;p&gt;In this article, we looked at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Number of Islands with recursive grid traversal&lt;/li&gt;
&lt;li&gt;Invert Binary Tree with recursion&lt;/li&gt;
&lt;li&gt;Course Schedule with topological sorting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And more importantly, we followed what changed while each algorithm was running.&lt;/p&gt;

&lt;p&gt;For Number of Islands, we watched connected land disappear as it became visited.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For Invert Binary Tree, we watched recursive calls go down and the tree change while they returned.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go down
↓
come back
↓
swap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For Course Schedule, we watched prerequisites disappear and new courses enter the queue.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;indegree--
↓
0 prerequisites
↓
queue.push()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is exactly the kind of thing I built &lt;strong&gt;DSA View View&lt;/strong&gt; for.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You can write or load a TypeScript implementation, run it with your own inputs, and move backward and forward through the runtime.&lt;/p&gt;

&lt;p&gt;If you are learning DSA too, try viewing one of these problems step by step.&lt;/p&gt;

&lt;p&gt;Especially when the implementation looks short, but your brain still says&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Wait... what just changed? 😿&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Seeing the runtime may make the idea much easier to follow.&lt;/p&gt;

&lt;p&gt;And if there is a DSA problem you want me to cover next, please let me know in the comments!&lt;/p&gt;

&lt;p&gt;I still have many algorithms to learn myself. 😸&lt;/p&gt;

&lt;p&gt;Let's train our DSA muscles together! 💪&lt;/p&gt;

&lt;p&gt;If you like DSA View View, please give it a star ⭐&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;
        dsa-view-view
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DSA View View allows you to understand DSA to see the data flow. 👀👀 Of course, it's free.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nyaomaru/dsa-view-view/./public/readme-view-view.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Freadme-view-view.png" alt="DSA View View" width="100%"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DSA View View&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;DSA View View turns TypeScript algorithm functions into step-by-step visual
stories. 👀👀&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-tv.gif" alt="DSA View View TV"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Write code, run it with structured inputs, and see the arrays, matrices
trees, lists, stacks, pointers, and return values move as the function executes.&lt;/p&gt;
&lt;p&gt;It is built for those moments when reading the code is not enough and you want
to &lt;em&gt;view&lt;/em&gt; why the answer changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-demo.gif" alt="DSA View View demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Try It?&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🧠 &lt;strong&gt;Step through real TypeScript&lt;/strong&gt;&lt;br&gt;
Paste or edit a function, validate it, then run the exact code in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🧩 &lt;strong&gt;Views that match the data&lt;/strong&gt;&lt;br&gt;
Arrays become bars, matrices become grids, trees become node graphs, linked lists become chains, and two-pointer area problems get their own visual view.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🌳 &lt;strong&gt;DSA-friendly inputs out of the box&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;TreeNode&lt;/code&gt;, &lt;code&gt;ListNode&lt;/code&gt;, &lt;code&gt;MinHeap&lt;/code&gt;, &lt;code&gt;MaxHeap&lt;/code&gt;, &lt;code&gt;PriorityQueue&lt;/code&gt;, nested arrays
matrices, strings, numbers, and class-style inputs are supported without
ceremony.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔎 &lt;strong&gt;39 built-in examples&lt;/strong&gt;&lt;br&gt;
Search by name, browse…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;See you in the next article!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>dsa</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Learn Valid Parentheses, Reverse Linked List, and Tree Max Depth with Step-by-Step Visualization in DSA View View 👀👀</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 26 Aug 2026 14:18:19 +0000</pubDate>
      <link>https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09</link>
      <guid>https://dev.to/nyaomaru/learn-valid-parentheses-reverse-linked-list-and-tree-max-depth-with-step-by-step-visualization-in-3o09</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I’m &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who struggles to make game sounds. 😿&lt;/p&gt;

&lt;p&gt;Have you used &lt;strong&gt;DSA View View&lt;/strong&gt; already? 👀👀&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__hidden-navigation-link"&gt;I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Features a timeline to step backward mid-loop&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4143027" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 15&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" id="article-link-4143027"&gt;
          I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;64&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              33&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;DSA View View allows you to understand DSA by visualizing how your implementation actually runs.&lt;/p&gt;

&lt;p&gt;In the previous article, we looked at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two Sum&lt;/li&gt;
&lt;li&gt;Binary Search&lt;/li&gt;
&lt;li&gt;Bubble Sort&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-story__hidden-navigation-link"&gt;Is Learning DSA Boring? Let's Use DSA View View 👀👀 (Two Sum, Binary Search, and Bubble Sort)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Visualizing execution logic changes mental models&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4408146" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 19&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" id="article-link-4408146"&gt;
          Is Learning DSA Boring? Let's Use DSA View View 👀👀 (Two Sum, Binary Search, and Bubble Sort)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/learning"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;learning&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;51&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              9&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;This time, let's try three more classic problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Valid Parentheses&lt;/li&gt;
&lt;li&gt;Reverse Linked List&lt;/li&gt;
&lt;li&gt;Maximum Depth of Binary Tree&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These problems introduce three very different ideas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stack
Pointer manipulation
Recursion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And all three can become confusing when we only stare at the final code.&lt;/p&gt;

&lt;p&gt;So let's view what actually happens. 👀&lt;/p&gt;

&lt;p&gt;I'm still learning DSA too, so let's learn together! 😸&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjb84e2mep057dzmcqikb.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjb84e2mep057dzmcqikb.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🥞 Valid Parentheses
&lt;/h2&gt;

&lt;p&gt;Let's start with &lt;strong&gt;Valid Parentheses&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose we have this string:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;()[]{}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Every opening bracket has a matching closing bracket.&lt;/p&gt;

&lt;p&gt;So this is valid. ✅&lt;/p&gt;

&lt;p&gt;But this&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;([)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;is not valid. ❌&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because the brackets close in the wrong order.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(
  [
)
  ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;[&lt;/code&gt; should be closed before the &lt;code&gt;(&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So how can we keep track of that order?&lt;/p&gt;
&lt;h3&gt;
  
  
  Use a Stack
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;stack&lt;/strong&gt; follows a simple rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The last thing we put in is the first thing we take out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is called &lt;strong&gt;LIFO&lt;/strong&gt; (Last In / First Out)&lt;/p&gt;

&lt;p&gt;Imagine stacking plates.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    🍽️  ← remove first
    🍽️
    🍽️
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The last plate we put on top is the first one we can take.&lt;/p&gt;

&lt;p&gt;Parentheses work in the same way.&lt;/p&gt;

&lt;p&gt;If we see:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(
[
{
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;then the brackets must close in reverse order&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;}
]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So a stack is a very natural fit.&lt;/p&gt;

&lt;p&gt;Here is the implementation:&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;function&lt;/span&gt; &lt;span class="nf"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&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="nx"&gt;boolean&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;stack&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="o"&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;pairs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{&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;for &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;char&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&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="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{&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;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&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="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&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;return&lt;/span&gt; &lt;span class="kc"&gt;false&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;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&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="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;pairs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;char&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="kc"&gt;false&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;return&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&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 important part is what happens to &lt;code&gt;stack&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's use&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;([])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At first&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stack = []
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We see&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It's an opening bracket.&lt;/p&gt;

&lt;p&gt;Push it.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stack = ["("]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Push again.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stack = ["(", "["]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is a closing bracket.&lt;/p&gt;

&lt;p&gt;What should it close?&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And what is currently on top of the stack?&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Perfect. ✅&lt;/p&gt;

&lt;p&gt;So we remove it.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stack = ["("]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It should close&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The top of the stack is also&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Pop!&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stack = []
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We reached the end with an empty stack.&lt;/p&gt;

&lt;p&gt;Valid! 🎉&lt;/p&gt;
&lt;h3&gt;
  
  
  What About an Invalid Example?
&lt;/h3&gt;

&lt;p&gt;Consider&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;([)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We start the same way.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(
↓
stack = ["("]

[
↓
stack = ["(", "["]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we find&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A &lt;code&gt;)&lt;/code&gt; needs&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But the top of our stack is&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;They don't match.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expected: (
actual:   [
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So we immediately know the string is invalid.&lt;/p&gt;
&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;We walk through the string once.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time:  O(n)
Space: O(n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the worst case, the stack may contain all opening brackets.&lt;/p&gt;
&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;This is where the stack becomes much easier to understand.&lt;/p&gt;

&lt;p&gt;When we only read.&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;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And&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;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It can be easy to lose track of what is actually inside the stack.&lt;/p&gt;

&lt;p&gt;Especially with something like.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;({[]})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What is on top right now?&lt;/p&gt;

&lt;p&gt;Which opening bracket are we trying to close?&lt;/p&gt;

&lt;p&gt;Instead of remembering everything in our head, we can follow the stack changing step by step.&lt;/p&gt;

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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoidmFsaWQtcGFyZW50aGVzZXMiLCJsIjoidHlwZXNjcmlwdCIsIm0iOiJ2ZXJpZmljYXRpb24iLCJ2IjoxfQ" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Conceptually, we can see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(
↓
[(]

{
↓
[(, {]

[
↓
[(, {, []

]
↓
[(, {]

}
↓
[(]

)
↓
[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's the whole idea.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember the opening brackets, and always match the most recent one first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Stack suddenly feels much less mysterious. 🥞😸&lt;/p&gt;


&lt;h2&gt;
  
  
  🔗 Reverse Linked List
&lt;/h2&gt;

&lt;p&gt;Next, let's reverse a linked list.&lt;/p&gt;

&lt;p&gt;Suppose we have&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 2 → 3 → 4 → 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We want&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5 → 4 → 3 → 2 → 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At first glance, this sounds simple.&lt;/p&gt;

&lt;p&gt;Just reverse it!&lt;/p&gt;

&lt;p&gt;But linked lists are a little different from arrays.&lt;/p&gt;

&lt;p&gt;With an array, the values live in positions like&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0  1  2  3  4
↓  ↓  ↓  ↓  ↓
1  2  3  4  5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A linked list instead consists of nodes pointing to the next node.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 2 → 3 → 4 → 5 → null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each arrow matters. To reverse the list, we need to reverse those arrows.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 ← 2 ← 3 ← 4 ← 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And this is where things can get confusing.&lt;/p&gt;

&lt;p&gt;Because if we change an arrow too early...&lt;/p&gt;

&lt;p&gt;we may lose the rest of the list. 😿&lt;/p&gt;
&lt;h3&gt;
  
  
  Three Important Variables
&lt;/h3&gt;

&lt;p&gt;A common iterative solution uses three variables&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prev
current
next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here is the implementation:&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;function&lt;/span&gt; &lt;span class="nf"&gt;reverseList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ListNode&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ListNode&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&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;prev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ListNode&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;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&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;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;next&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;prev&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;It's short.&lt;/p&gt;

&lt;p&gt;But there is a lot happening inside these few lines.&lt;/p&gt;

&lt;p&gt;Let's follow it carefully.&lt;/p&gt;

&lt;p&gt;We start with&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 2 → 3 → null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prev = null
current = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 1: Save the Next Node
&lt;/h3&gt;

&lt;p&gt;First&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;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;next = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Why do we need this?&lt;/p&gt;

&lt;p&gt;Because we're about to change&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If we change that arrow without remembering &lt;code&gt;2&lt;/code&gt;, we lose access to the rest of the list.&lt;/p&gt;

&lt;p&gt;So first&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Save where we need to go next.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Step 2: Reverse the Arrow
&lt;/h3&gt;

&lt;p&gt;Now&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;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Originally&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But &lt;code&gt;prev&lt;/code&gt; is&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The first arrow has been reversed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: Move &lt;code&gt;prev&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Next&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;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prev = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 4: Move &lt;code&gt;current&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Finally&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;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We saved &lt;code&gt;2&lt;/code&gt; earlier.&lt;/p&gt;

&lt;p&gt;So now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Our state looks 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;null ← 1    2 → 3 → null
       ↑    ↑
      prev current
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we do exactly the same thing again.&lt;/p&gt;

&lt;p&gt;Save:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;next = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Reverse&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 → 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Move&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prev = 2
current = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;null ← 1 ← 2    3 → null
           ↑    ↑
          prev  current
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;One more time&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;next = null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Reverse&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3 → 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Move&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prev = 3
current = null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;null ← 1 ← 2 ← 3
               ↑
              prev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The loop stops because&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current === null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And &lt;code&gt;prev&lt;/code&gt; is the new head.&lt;/p&gt;

&lt;p&gt;So&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;return&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Done! 🎉&lt;/p&gt;
&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;We visit each node once.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time:  O(n)
Space: O(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We don't create another linked list.&lt;/p&gt;

&lt;p&gt;We only move a few pointers.&lt;/p&gt;
&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;This is exactly the kind of code that I find difficult to understand by reading alone.&lt;/p&gt;

&lt;p&gt;These four lines:&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;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;look simple.&lt;/p&gt;

&lt;p&gt;But when I first see code like this, my brain starts asking.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Wait.

- Where is current now?
- Did we lose next?
- Which arrow changed?
- What exactly does prev point to?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;😿&lt;/p&gt;

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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoicmV2ZXJzZS1saXN0IiwibCI6InR5cGVzY3JpcHQiLCJtIjoidmVyaWZpY2F0aW9uIiwidiI6MX0" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;When we visualize each step, we can actually follow the pointers moving.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prev      current
 ↓           ↓
null         1 → 2 → 3

      ↓↓↓

null ← 1     2 → 3
       ↑     ↑
      prev current

      ↓↓↓

null ← 1 ← 2     3
           ↑     ↑
          prev current

      ↓↓↓

null ← 1 ← 2 ← 3
               ↑
              prev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The algorithm becomes much simpler when we stop thinking of it as four mysterious assignments.&lt;/p&gt;

&lt;p&gt;It's really just&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Save next
  ↓
Reverse arrow
  ↓
Move prev
  ↓
Move current
  ↓
Repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Nice! 🔗😸&lt;/p&gt;


&lt;h2&gt;
  
  
  🌳 Maximum Depth of Binary Tree
&lt;/h2&gt;

&lt;p&gt;Finally, let's look at a tree.&lt;/p&gt;

&lt;p&gt;Consider this binary tree.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        3
       / \
      9   20
         /  \
        15   7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What is its maximum depth?&lt;/p&gt;

&lt;p&gt;The longest path from the root to a leaf contains three nodes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3
↓
20
↓
15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So the answer is.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;How can we calculate that?&lt;/p&gt;
&lt;h3&gt;
  
  
  Think About a Smaller Tree
&lt;/h3&gt;

&lt;p&gt;Suppose we are standing at one node.&lt;/p&gt;

&lt;p&gt;We don't really need to understand the entire tree at once.&lt;/p&gt;

&lt;p&gt;We only need to ask.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How deep is the left subtree?

How deep is the right subtree?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then choose the larger one.&lt;/p&gt;

&lt;p&gt;And add &lt;code&gt;1&lt;/code&gt; for the current node.&lt;/p&gt;

&lt;p&gt;That's exactly what this implementation does.&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;function&lt;/span&gt; &lt;span class="nf"&gt;maxDepth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TreeNode&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&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="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&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="mi"&gt;0&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;leftDepth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;maxDepth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&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;rightDepth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;maxDepth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leftDepth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rightDepth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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 important idea is&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leftDepth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rightDepth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;But recursion can feel strange.&lt;/p&gt;

&lt;p&gt;When we call&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;maxDepth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;where does the current function go?&lt;/p&gt;

&lt;p&gt;And how do all those calls eventually become one number?&lt;/p&gt;

&lt;p&gt;Let's follow a small example.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    1
   / \
  2   3
 /
4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We start at&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But before &lt;code&gt;1&lt;/code&gt; can know its depth, it asks its left child&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;maxDepth(2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Node &lt;code&gt;2&lt;/code&gt; asks&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;maxDepth(4)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Node &lt;code&gt;4&lt;/code&gt; has no children.&lt;/p&gt;

&lt;p&gt;So both sides eventually reach&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And&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;maxDepth&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;returns&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Therefore node &lt;code&gt;4&lt;/code&gt; can calculate&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;max(0, 0) + 1
= 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we return to node &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Its left side has depth&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Its right side is &lt;code&gt;null&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;max(1, 0) + 1
= 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now return to node &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Eventually its right subtree also returns&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So node &lt;code&gt;1&lt;/code&gt; gets&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;leftDepth = 2
rightDepth = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And calculates&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;max(2, 1) + 1
= 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Answer&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;🎉&lt;/p&gt;
&lt;h3&gt;
  
  
  The Interesting Part: Going Down and Coming Back Up
&lt;/h3&gt;

&lt;p&gt;This is what makes recursion interesting.&lt;/p&gt;

&lt;p&gt;First, the function calls go &lt;strong&gt;down&lt;/strong&gt; the tree.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
↓
2
↓
4
↓
null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But the answers are built while returning &lt;strong&gt;back up&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;null → 0
4    → 1
2    → 2
1    → 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So recursion isn't only&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep calling the same function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are really two directions.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Go down
  ↓
Reach the base case
  ↓
Return values back up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The base case here is&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="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&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="mi"&gt;0&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;Without it, the recursion would have no place to stop.&lt;/p&gt;
&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;Every node is visited once.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time: O(n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The recursive call stack depends on the height of the tree.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Space: O(h)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;where &lt;code&gt;h&lt;/code&gt; is the height of the tree.&lt;/p&gt;

&lt;p&gt;For a balanced tree, that is roughly&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;O(log n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the worst case, if the tree looks like a linked list&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
 \
  2
   \
    3
     \
      4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;the depth can become&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;O(n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;Recursion is probably my favorite example for visualization.&lt;/p&gt;

&lt;p&gt;Because the final implementation is tiny&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;leftDepth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;maxDepth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&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;rightDepth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;maxDepth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leftDepth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rightDepth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;But a lot is hidden inside those function calls.&lt;/p&gt;

&lt;p&gt;When reading the code, it can feel like&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;maxDepth()
inside maxDepth()
inside maxDepth()
inside maxDepth()
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Where are we now? 😿&lt;/p&gt;

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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoidHJlZS1kZXB0aCIsImwiOiJ0eXBlc2NyaXB0IiwibSI6InZlcmlmaWNhdGlvbiIsInYiOjF9" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;When we step through the execution, we can follow both parts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Going down

1
↓
2
↓
4
↓
null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and then&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Coming back

null → 0
↓
4 → 1
↓
2 → 2
↓
1 → 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That makes the recursive idea much easier to see.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ask the smaller subproblems for their answers, then use those answers to build the current answer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🌳😸&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 What Did We Actually Learn?
&lt;/h2&gt;

&lt;p&gt;These three problems look completely different.&lt;/p&gt;

&lt;p&gt;But each one introduces a very useful way of thinking.&lt;/p&gt;
&lt;h3&gt;
  
  
  Valid Parentheses
&lt;/h3&gt;

&lt;p&gt;Use a stack when the most recent item needs to be handled first.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What was the last thing I opened?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Reverse Linked List
&lt;/h3&gt;

&lt;p&gt;When changing references, save what you still need before breaking the old connection.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Where do I need to go next before I change this pointer?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Maximum Depth of Binary Tree
&lt;/h3&gt;

&lt;p&gt;Break a problem into smaller versions of the same problem.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can I get the answers from my children and build my answer from them?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is one reason I like learning these problems together.&lt;/p&gt;

&lt;p&gt;The implementations are not very large.&lt;/p&gt;

&lt;p&gt;But each one introduces a completely different mental model&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stack
Pointer
Recursion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And those mental models are much harder to learn than the syntax itself.&lt;/p&gt;

&lt;p&gt;Sometimes the code tells us &lt;strong&gt;what happens&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But I also want to see &lt;strong&gt;how it happens&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I want to view it. 👀👀&lt;/p&gt;


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

&lt;p&gt;In this article, we looked at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Valid Parentheses with a stack&lt;/li&gt;
&lt;li&gt;Reverse Linked List with pointer manipulation&lt;/li&gt;
&lt;li&gt;Maximum Depth of Binary Tree with recursion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And more importantly, we followed the state while each algorithm was running.&lt;/p&gt;

&lt;p&gt;We watched change the stack.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stack.push() / stack.pop()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We watched move through a linked list.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prev
current
next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And we watched recursive calls travel down a tree and return their answers back up.&lt;/p&gt;

&lt;p&gt;This is exactly the kind of thing I built &lt;strong&gt;DSA View View&lt;/strong&gt; for.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You can write or load a TypeScript implementation, run it with your own inputs, and move backward and forward through the runtime.&lt;/p&gt;

&lt;p&gt;If you are learning DSA too, try viewing one of these problems step by step.&lt;/p&gt;

&lt;p&gt;Especially if a solution feels like&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I understand every line individually... but somehow I still don't understand the whole thing. 😿&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Seeing the runtime may connect those pieces together.&lt;/p&gt;

&lt;p&gt;And if there is a DSA problem you want me to cover next, please let me know in the comments!&lt;/p&gt;

&lt;p&gt;I still have many algorithms to learn myself. 😸&lt;/p&gt;

&lt;p&gt;Let's train our DSA muscles together! 💪&lt;/p&gt;

&lt;p&gt;If you like DSA View View, please give it a star ⭐&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;
        dsa-view-view
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DSA View View allows you to understand DSA to see the data flow. 👀👀 Of course, it's free.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nyaomaru/dsa-view-view/./public/readme-view-view.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Freadme-view-view.png" alt="DSA View View" width="100%"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DSA View View&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;DSA View View turns TypeScript algorithm functions into step-by-step visual
stories. 👀👀&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-tv.gif" alt="DSA View View TV"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Write code, run it with structured inputs, and see the arrays, matrices
trees, lists, stacks, pointers, and return values move as the function executes.&lt;/p&gt;
&lt;p&gt;It is built for those moments when reading the code is not enough and you want
to &lt;em&gt;view&lt;/em&gt; why the answer changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-demo.gif" alt="DSA View View demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Try It?&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🧠 &lt;strong&gt;Step through real TypeScript&lt;/strong&gt;&lt;br&gt;
Paste or edit a function, validate it, then run the exact code in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🧩 &lt;strong&gt;Views that match the data&lt;/strong&gt;&lt;br&gt;
Arrays become bars, matrices become grids, trees become node graphs, linked lists become chains, and two-pointer area problems get their own visual view.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🌳 &lt;strong&gt;DSA-friendly inputs out of the box&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;TreeNode&lt;/code&gt;, &lt;code&gt;ListNode&lt;/code&gt;, &lt;code&gt;MinHeap&lt;/code&gt;, &lt;code&gt;MaxHeap&lt;/code&gt;, &lt;code&gt;PriorityQueue&lt;/code&gt;, nested arrays
matrices, strings, numbers, and class-style inputs are supported without
ceremony.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔎 &lt;strong&gt;39 built-in examples&lt;/strong&gt;&lt;br&gt;
Search by name, browse…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;See you in the next article!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>opensource</category>
      <category>dsa</category>
    </item>
    <item>
      <title>Is Learning DSA Boring? Let's Use DSA View View 👀👀 (Two Sum, Binary Search, and Bubble Sort)</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 19 Aug 2026 14:43:44 +0000</pubDate>
      <link>https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o</link>
      <guid>https://dev.to/nyaomaru/is-learning-dsa-boring-lets-use-dsa-view-view-two-sum-binary-search-and-bubble-sort-374o</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I’m &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who dislikes crowded places, so I'm planning to take a quiet vacation in September. 🏝️&lt;/p&gt;

&lt;p&gt;Have you used &lt;strong&gt;DSA View View&lt;/strong&gt; already? 👀👀&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__hidden-navigation-link"&gt;I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Features a timeline to step backward mid-loop&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4143027" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 15&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" id="article-link-4143027"&gt;
          I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;64&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              33&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;DSA View View allows you to understand DSA by visualizing how your implementation actually runs.&lt;/p&gt;

&lt;p&gt;But just introducing the tool is not enough.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can it actually help us understand DSA?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article, we'll walk through three classic problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two Sum&lt;/li&gt;
&lt;li&gt;Binary Search&lt;/li&gt;
&lt;li&gt;Bubble Sort&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll first understand the algorithm, and then see what is actually happening with &lt;strong&gt;DSA View View&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw6oxvyvuatcas2ogxgya.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw6oxvyvuatcas2ogxgya.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's learn together! 😸&lt;/p&gt;




&lt;h2&gt;
  
  
  🗺️ Two Sum
&lt;/h2&gt;

&lt;p&gt;Let's start with a very famous problem.&lt;/p&gt;

&lt;p&gt;Given an array of numbers and a target value, find the indices of two numbers whose sum equals the target.&lt;/p&gt;

&lt;p&gt;For example,&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;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The answer is&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="mi"&gt;0&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;Because&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 + 7 = 9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Simple!&lt;/p&gt;

&lt;p&gt;So, how should we find them? 🤔&lt;/p&gt;
&lt;h3&gt;
  
  
  Brute Force
&lt;/h3&gt;

&lt;p&gt;The easiest approach is probably checking every possible pair.&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;function&lt;/span&gt; &lt;span class="nf"&gt;twoSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;for &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;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;target&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;j&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;return&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;This works.&lt;/p&gt;

&lt;p&gt;But if the array becomes large, we may need to compare a lot of pairs, right?&lt;/p&gt;

&lt;p&gt;The time complexity is &lt;em&gt;O(n²)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Can we avoid checking the same values again and again?&lt;/p&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;Let's use a &lt;code&gt;Map&lt;/code&gt;.&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;function&lt;/span&gt; &lt;span class="nf"&gt;twoSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&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;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&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="p"&gt;,&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="k"&gt;for &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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;need&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;current&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="nx"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;need&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;need&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;seen&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;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&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="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 important part is 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;need&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Instead of asking&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which two numbers should I combine?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;we ask&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What number do I need to complete the target?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's follow the example.&lt;/p&gt;

&lt;p&gt;At first&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current = 2
target = 9

need = 9 - 2
     = 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Have we already seen &lt;code&gt;7&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;So we remember &lt;code&gt;2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;seen = {
  2 → 0
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current = 7
target = 9

need = 9 - 7
     = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Have we already seen &lt;code&gt;2&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Yes! 👀👀&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;seen = {
  2 → 0
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So&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;return&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="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;Done!&lt;/p&gt;

&lt;p&gt;Because we only need to walk through the array once, the time complexity becomes.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time:  O(n)
Space: O(n)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;The implementation is quite small.&lt;/p&gt;

&lt;p&gt;But when I was first learning this pattern, this part still felt a little magical.&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="nx"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;need&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Where did &lt;code&gt;need&lt;/code&gt; come from?&lt;/li&gt;
&lt;li&gt;What is inside &lt;code&gt;seen&lt;/code&gt; at this moment?&lt;/li&gt;
&lt;li&gt;Why does checking the previous values solve the problem?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly where visualization helps.&lt;/p&gt;

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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoidHdvLXN1bSIsImwiOiJ0eXBlc2NyaXB0IiwibSI6InZlcmlmaWNhdGlvbiIsInYiOjF9" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;With DSA View View, we can move through the runtime one step at a time and inspect how the values change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2
↓
Need 7
↓
Remember 2
↓
7
↓
Need 2
↓
Found 2!
🎉
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now the &lt;code&gt;Map&lt;/code&gt; is not just some mysterious trick.&lt;/p&gt;

&lt;p&gt;We can actually follow the idea.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember what we have already seen, and check whether the value we need is there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nice! 😸&lt;/p&gt;


&lt;h2&gt;
  
  
  🔍 Binary Search
&lt;/h2&gt;

&lt;p&gt;Next is &lt;strong&gt;Binary Search&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose we have this sorted array&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 3, 5, 7, 9, 11, 13]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And we want to find&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Of course, we could start from &lt;code&gt;1&lt;/code&gt; and check every number.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 3 → 5 → 7 → 9 → 11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That works.&lt;/p&gt;

&lt;p&gt;But Binary Search does something smarter.&lt;/p&gt;

&lt;p&gt;Instead of checking from the beginning, it checks the &lt;strong&gt;middle&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 3, 5, 7, 9, 11, 13]
          ↑
         mid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Our middle value is &lt;code&gt;7&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We are looking for &lt;code&gt;11&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;11 &amp;gt; 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Because the array is sorted, we already know something very useful.&lt;/p&gt;

&lt;p&gt;Everything on the left side of &lt;code&gt;7&lt;/code&gt; is also smaller than &lt;code&gt;11&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, we don't need that half anymore. 👋&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 3, 5, 7, 9, 11, 13]
             └───────┘
               search
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we check the middle of the remaining range.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[9, 11, 13]
     ↑
    mid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;11 === 11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Found it! 🎉&lt;/p&gt;

&lt;p&gt;Here is the implementation.&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;function&lt;/span&gt; &lt;span class="nf"&gt;binarySearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&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;left&lt;/span&gt; &lt;span class="o"&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;let&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;right&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;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&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="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;target&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;mid&lt;/span&gt;&lt;span class="p"&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="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&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;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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;There are three important variables.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;left
right
mid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;They represent the current search range.&lt;/p&gt;

&lt;p&gt;For our example, they start 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;left = 0
right = 6
mid = 3

[1, 3, 5, 7, 9, 11, 13]
 ↑        ↑          ↑
left     mid       right
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Because&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;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we move &lt;code&gt;left&lt;/code&gt;.&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;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mid&lt;/span&gt; &lt;span class="o"&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;Now&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 3, 5, 7, 9, 11, 13]
             ↑   ↑   ↑
           left mid right
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And &lt;code&gt;11&lt;/code&gt; is found.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Is Binary Search Fast?
&lt;/h3&gt;

&lt;p&gt;This is the interesting part.&lt;/p&gt;

&lt;p&gt;Each step removes about &lt;strong&gt;half of the remaining candidates&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If there are 1,000 values, we don't necessarily need 1,000 checks.&lt;/p&gt;

&lt;p&gt;It becomes roughly&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1000
↓
500
↓
250
↓
125
↓
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's why Binary Search has&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time:  O(log n)
Space: O(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But there is one very important condition.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The data must be sorted.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Without sorted data, we cannot safely throw away half of the search range.&lt;/p&gt;
&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;Binary Search is one of the algorithms that made me want a visualization tool in the first place.&lt;/p&gt;

&lt;p&gt;The code itself is short&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;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mid&lt;/span&gt; &lt;span class="o"&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;or&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;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mid&lt;/span&gt; &lt;span class="o"&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;Easy.&lt;/p&gt;

&lt;p&gt;But when learning it, I sometimes found myself thinking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Wait... which part are we searching now? 😿&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/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa8rn3wiojw0c29vifm5n.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa8rn3wiojw0c29vifm5n.gif" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoiYmluYXJ5LXNlYXJjaCIsImwiOiJ0eXBlc2NyaXB0IiwibSI6InZlcmlmaWNhdGlvbiIsInYiOjF9" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;When we visualize &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;mid&lt;/code&gt;, and &lt;code&gt;right&lt;/code&gt;, the idea becomes much easier to follow.&lt;/p&gt;

&lt;p&gt;We are not randomly changing three numbers.&lt;/p&gt;

&lt;p&gt;We are continuously shrinking the search area.&lt;br&gt;
&lt;/p&gt;

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

       ↓

        ███████

       ↓

          ███

       ↓

           █
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's Binary Search!&lt;/p&gt;

&lt;p&gt;Cut the unnecessary half.&lt;/p&gt;

&lt;p&gt;Then cut it again. And again. And again.&lt;/p&gt;

&lt;p&gt;Until we find the answer. ✂️😸&lt;/p&gt;


&lt;h2&gt;
  
  
  🫧 Bubble Sort
&lt;/h2&gt;

&lt;p&gt;Finally, let's sort something!&lt;/p&gt;

&lt;p&gt;Consider this array.&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="mi"&gt;5&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;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We want.&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Bubble Sort repeatedly compares &lt;strong&gt;two neighboring values&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If they are in the wrong order, it swaps them.&lt;/p&gt;

&lt;p&gt;Let's look at the beginning.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[5, 1, 4, 2, 8]
 ↑  ↑
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Compare&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5 &amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So swap them.&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, 4, 2, 8]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next&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, 4, 2, 8]
    ↑  ↑
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Again&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5 &amp;gt; 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Swap!&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 4, 5, 2, 8]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And continue.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 4, 5, 2, 8]
       ↑  ↑

5 &amp;gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Swap!&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 4, 2, 5, 8]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Eventually, larger values move toward the end of the array.&lt;/p&gt;

&lt;p&gt;They kind of...&lt;/p&gt;

&lt;p&gt;bubble up. 🫧&lt;/p&gt;

&lt;p&gt;That's why it is called &lt;strong&gt;Bubble Sort&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is a simple implementation:&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;function&lt;/span&gt; &lt;span class="nf"&gt;bubbleSort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;for &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;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&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;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&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;return&lt;/span&gt; &lt;span class="nx"&gt;nums&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;We repeatedly compare&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;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And&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;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&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;and swap them when necessary.&lt;/p&gt;

&lt;p&gt;After one full pass, the largest remaining value reaches its correct position near the end.&lt;/p&gt;

&lt;p&gt;So on the next pass, we don't need to check that position again.&lt;/p&gt;

&lt;p&gt;That's why the inner loop contains.&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;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&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;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;Bubble Sort isn't very fast for large arrays.&lt;/p&gt;

&lt;p&gt;Its time complexity is&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time:  O(n²)
Space: O(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So I probably won't suddenly replace production sorting with Bubble Sort tomorrow. 😸&lt;/p&gt;

&lt;p&gt;But as a learning example, I really like it.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because you can &lt;strong&gt;see the algorithm working&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  👀 Let's View View It
&lt;/h3&gt;

&lt;p&gt;This is probably the most visually satisfying one of the three.&lt;/p&gt;

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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app/#s=j.eyJlIjoiYnViYmxlLXNvcnQiLCJsIjoidHlwZXNjcmlwdCIsIm0iOiJ2ZXJpZmljYXRpb24iLCJ2IjoxfQ" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Instead of only reading&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="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;we can follow the values moving through the array.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[5, 1, 4, 2, 8]

 ↓ swap

[1, 5, 4, 2, 8]

    ↓ swap

[1, 4, 5, 2, 8]

       ↓ swap

[1, 4, 2, 5, 8]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then another pass begins.&lt;/p&gt;

&lt;p&gt;The code contains nested loops, indexes, comparisons, and swaps.&lt;/p&gt;

&lt;p&gt;But visually, the basic rule is extremely simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compare neighbors. If the left one is bigger, swap them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Repeat. Repeat. Repeat.&lt;/p&gt;

&lt;p&gt;Sorted! 🎉&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 What Did We Actually Learn?
&lt;/h2&gt;

&lt;p&gt;These three problems look quite different.&lt;/p&gt;

&lt;p&gt;But each one introduces a useful way of thinking.&lt;/p&gt;
&lt;h3&gt;
  
  
  Two Sum
&lt;/h3&gt;

&lt;p&gt;Remember information from previous steps.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Have I already seen what I need?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Binary Search
&lt;/h3&gt;

&lt;p&gt;Use what we already know to remove impossible candidates.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can I safely discard half of the search space?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Bubble Sort
&lt;/h3&gt;

&lt;p&gt;Break a larger problem into many small comparisons.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Are these two values in the correct order?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is one of the things I find interesting about learning DSA.&lt;/p&gt;

&lt;p&gt;At first, the implementation can look like a collection of indexes, loops, conditions, and mysterious variables.&lt;/p&gt;

&lt;p&gt;But behind the code, there is usually a much simpler idea.&lt;/p&gt;

&lt;p&gt;And sometimes I don't fully understand that idea just by staring at the code.&lt;/p&gt;

&lt;p&gt;I want to &lt;strong&gt;view it&lt;/strong&gt;. 👀👀&lt;/p&gt;


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

&lt;p&gt;In this article, we looked at three classic algorithms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two Sum with a &lt;code&gt;Map&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Binary Search&lt;/li&gt;
&lt;li&gt;Bubble Sort&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And more importantly, we looked at &lt;strong&gt;how the data changes while they run&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I think this is where visualization can be especially useful.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading the final implementation tells us &lt;strong&gt;what the code is&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Stepping through it helps us understand &lt;strong&gt;why it works&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's exactly why I built DSA View View.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://dsa-view-view.vercel.app" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;dsa-view-view.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You can write or load a TypeScript implementation, run it with your own inputs, and move backward and forward through the runtime.&lt;/p&gt;

&lt;p&gt;If you are learning DSA too, try taking a problem you already solved and viewing it step by step.&lt;/p&gt;

&lt;p&gt;You may notice something you didn't notice when only reading the code. 👀&lt;/p&gt;

&lt;p&gt;And if there is a DSA problem you want me to cover next, please let me know in the comments!&lt;/p&gt;

&lt;p&gt;I still have many algorithms to learn myself. 😸&lt;/p&gt;

&lt;p&gt;Let's train our DSA muscles together! 💪&lt;/p&gt;

&lt;p&gt;If you like DSA View View, please give it a star ⭐&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;
        dsa-view-view
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DSA View View allows you to understand DSA to see the data flow. 👀👀 Of course, it's free.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nyaomaru/dsa-view-view/./public/readme-view-view.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Freadme-view-view.png" alt="DSA View View" width="100%"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DSA View View&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;DSA View View turns TypeScript algorithm functions into step-by-step visual
stories. 👀👀&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-tv.gif" alt="DSA View View TV"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Write code, run it with structured inputs, and see the arrays, matrices
trees, lists, stacks, pointers, and return values move as the function executes.&lt;/p&gt;
&lt;p&gt;It is built for those moments when reading the code is not enough and you want
to &lt;em&gt;view&lt;/em&gt; why the answer changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-demo.gif" alt="DSA View View demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Try It?&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🧠 &lt;strong&gt;Step through real TypeScript&lt;/strong&gt;&lt;br&gt;
Paste or edit a function, validate it, then run the exact code in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🧩 &lt;strong&gt;Views that match the data&lt;/strong&gt;&lt;br&gt;
Arrays become bars, matrices become grids, trees become node graphs, linked lists become chains, and two-pointer area problems get their own visual view.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🌳 &lt;strong&gt;DSA-friendly inputs out of the box&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;TreeNode&lt;/code&gt;, &lt;code&gt;ListNode&lt;/code&gt;, &lt;code&gt;MinHeap&lt;/code&gt;, &lt;code&gt;MaxHeap&lt;/code&gt;, &lt;code&gt;PriorityQueue&lt;/code&gt;, nested arrays
matrices, strings, numbers, and class-style inputs are supported without
ceremony.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔎 &lt;strong&gt;39 built-in examples&lt;/strong&gt;&lt;br&gt;
Search by name, browse…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;And my DSA View View has launched at TinyLaunch! 🚀 Please take a loot 👇&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://www.tinylaunch.com/launch/17804-dsa-view-view" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;tinylaunch.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;See you in the next article!&lt;/p&gt;

</description>
      <category>dsa</category>
      <category>typescript</category>
      <category>opensource</category>
      <category>learning</category>
    </item>
    <item>
      <title>is-kit Reached 50 Stars ⭐ Here’s How We Use It in Production</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 12 Aug 2026 13:16:48 +0000</pubDate>
      <link>https://dev.to/nyaomaru/is-kit-reached-50-stars-heres-how-we-use-it-in-production-2i5b</link>
      <guid>https://dev.to/nyaomaru/is-kit-reached-50-stars-heres-how-we-use-it-in-production-2i5b</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I'm &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who is trying to lose weight. 🐖🙀&lt;/p&gt;

&lt;p&gt;I maintain a type guard library, &lt;code&gt;is-kit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I spend an unreasonable amount of time asking&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“But what if this value is actually &lt;code&gt;unknown&lt;/code&gt;???”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Recently, &lt;a href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;&lt;code&gt;is-kit&lt;/code&gt;&lt;/a&gt; crossed &lt;strong&gt;50 GitHub stars&lt;/strong&gt; 🎉🎉🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fomyd3e9bikp2q5l493gs.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A star is not a benchmark. And 50 stars do not suddenly make a library production-ready.&lt;/p&gt;

&lt;p&gt;But each one still means&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Someone found this idea useful.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That makes me very happy!! Each star gives me more motivation to keep improving the library!!!!&lt;/p&gt;

&lt;p&gt;There is also something more concrete I want to share&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; is now used in a production TypeScript application serving more than 100,000 users. 🚀 &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article explains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What problem we had&lt;/li&gt;
&lt;li&gt;How we introduced &lt;code&gt;is-kit&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;What actually changed&lt;/li&gt;
&lt;li&gt;Where it is used today&lt;/li&gt;
&lt;li&gt;What its practical advantages are&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dive in!&lt;/p&gt;




&lt;h2&gt;
  
  
  📋 The Problem Was Not “Validation”
&lt;/h2&gt;

&lt;p&gt;The application already had many small checks like 👇&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;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&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;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;value&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;||&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It also had user-defined type guards for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP client errors&lt;/li&gt;
&lt;li&gt;Status codes&lt;/li&gt;
&lt;li&gt;Literal unions&lt;/li&gt;
&lt;li&gt;Arrays&lt;/li&gt;
&lt;li&gt;Plain objects&lt;/li&gt;
&lt;li&gt;Values coming from JSON or API responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each check was reasonable by itself.&lt;/p&gt;

&lt;p&gt;The problem appeared when they started repeating.&lt;/p&gt;

&lt;p&gt;For example, several error guards had almost the same structure.&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;type&lt;/span&gt; &lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;isHttpClientError&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="nl"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&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;function&lt;/span&gt; &lt;span class="nf"&gt;isUnauthorizedError&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="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;HttpClientError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;isHttpClientError&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isValidationError&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="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;HttpClientError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;isHttpClientError&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;422&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;This works.&lt;/p&gt;

&lt;p&gt;But it has three practical problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The same base check is repeated&lt;/li&gt;
&lt;li&gt;Assertion casts appear inside every guard&lt;/li&gt;
&lt;li&gt;Adding another status means adding another copy&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code was not broken.&lt;/p&gt;

&lt;p&gt;It was simply asking for a reusable abstraction. 🔧&lt;/p&gt;


&lt;h2&gt;
  
  
  🏃‍♂️ The Production Pattern
&lt;/h2&gt;

&lt;p&gt;We replaced the repeated checks with small composable guards.&lt;/p&gt;

&lt;p&gt;Here is a business-neutral version of the production pattern.&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;equalsKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;or&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="s2"&gt;is-kit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;isHttpClientError&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="nl"&gt;code&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="nl"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&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;isHttpClientError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HttpClientError&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;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;equalsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isHttpClientError&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;value&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;isHttpErrorWithStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;define&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="o"&gt;&amp;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;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;isHttpClientError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;status&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;const&lt;/span&gt; &lt;span class="nx"&gt;isUnauthorizedError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;isHttpErrorWithStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&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;const&lt;/span&gt; &lt;span class="nx"&gt;isValidationError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;isHttpErrorWithStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;422&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;hasTimeoutCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="o"&gt;&amp;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;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;isHttpClientError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TIMEOUT&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasTimeoutMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="o"&gt;&amp;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;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;isHttpClientError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timed out&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;const&lt;/span&gt; &lt;span class="nx"&gt;isTimeoutError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasTimeoutCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hasTimeoutMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;There are a few important details here.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;define&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;define&amp;lt;T&amp;gt;&lt;/code&gt; turns a runtime boolean check into a reusable predicate.&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;isHttpErrorWithStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;define&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="o"&gt;&amp;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 responsibility is still ours. The runtime check must actually prove &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; cannot make an incorrect predicate correct.&lt;/p&gt;

&lt;p&gt;But it gives custom guards one consistent shape.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;equalsKey&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The base error is not plain JSON.&lt;/p&gt;

&lt;p&gt;It is an error instance with a marker property.&lt;/p&gt;

&lt;p&gt;So a plain-object schema is not the right abstraction here.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;equalsKey("isHttpClientError", true)&lt;/code&gt; expresses exactly what we need,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This value owns this key, and its value is exactly &lt;code&gt;true&lt;/code&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;or&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A timeout can be detected in more than one way.&lt;/p&gt;

&lt;p&gt;Instead of creating another large conditional, we compose two reusable guards.&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;isTimeoutError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasTimeoutCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hasTimeoutMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That is the core idea of &lt;code&gt;is-kit&lt;/code&gt;,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Build small guards, then compose them.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  ✨ What Actually Changed
&lt;/h2&gt;

&lt;p&gt;The first adoption refactor was not just 👇&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add is-kit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It changed the structure of the guard layer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Observable result&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Error guards&lt;/td&gt;
&lt;td&gt;7 separate modules became 1 shared module&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adoption diff&lt;/td&gt;
&lt;td&gt;335 lines added, 584 removed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Net diff&lt;/td&gt;
&lt;td&gt;249 fewer lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Direct imports today&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;is-kit&lt;/code&gt; is isolated to 7 app helper modules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App reach today&lt;/td&gt;
&lt;td&gt;Those helpers are consumed by 39 non-test source files&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The diff includes rewritten tests and helper adapters, so &lt;strong&gt;249 fewer lines is not a claim that a library magically deletes code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is the measured result of that specific consolidation.&lt;/p&gt;

&lt;p&gt;The more important change is the shape.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;is-kit primitives
       ↓
app guard helpers
       ↓
features, routes, services, and UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The production application does not import &lt;code&gt;is-kit&lt;/code&gt; from every component.&lt;/p&gt;

&lt;p&gt;Instead, most call sites use application-owned helpers.&lt;/p&gt;


&lt;h2&gt;
  
  
  🤔 Why Keep an Application Boundary?
&lt;/h2&gt;

&lt;p&gt;For primitives, the application wraps or re-exports the library guards 👇&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;isNumber&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;isFiniteNumberGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isNumberPrimitive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isString&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;isStringGuard&lt;/span&gt;&lt;span class="p"&gt;,&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="s2"&gt;is-kit&lt;/span&gt;&lt;span class="dl"&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;const&lt;/span&gt; &lt;span class="nx"&gt;isString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isStringGuard&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;const&lt;/span&gt; &lt;span class="nx"&gt;isNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isNumberPrimitive&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;const&lt;/span&gt; &lt;span class="nx"&gt;isFiniteNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isFiniteNumberGuard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This looks like a small detail, but it is an important design choice.&lt;/p&gt;

&lt;p&gt;JavaScript has more than one useful meaning for “number”.&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;typeof&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&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 the application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;isNumber&lt;/code&gt; follows primitive &lt;code&gt;typeof&lt;/code&gt; semantics&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isFiniteNumber&lt;/code&gt; rejects &lt;code&gt;NaN&lt;/code&gt; and &lt;code&gt;Infinity&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application owns those names. &lt;code&gt;is-kit&lt;/code&gt; provides the reusable implementation.&lt;/p&gt;

&lt;p&gt;This boundary also means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call sites do not depend on library naming decisions&lt;/li&gt;
&lt;li&gt;Semantics stay consistent across the app&lt;/li&gt;
&lt;li&gt;A future migration has one clear place to start&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how I prefer to introduce small libraries into large applications.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Adopt them behind a local vocabulary.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  😎 Other Real Usage Patterns
&lt;/h2&gt;

&lt;p&gt;The HTTP error guards are the largest example, but not the only one.&lt;/p&gt;
&lt;h3&gt;
  
  
  Arrays
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&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;arrayOf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isNumberPrimitive&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="s2"&gt;is-kit&lt;/span&gt;&lt;span class="dl"&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;const&lt;/span&gt; &lt;span class="nx"&gt;isNumberArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;arrayOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isNumberPrimitive&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This replaces&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;isNumberArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&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;is&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Literal unions
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&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;oneOfValues&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="s2"&gt;is-kit&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;VIEW_MODES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compact&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comfortable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&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;isViewMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;oneOfValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;VIEW_MODES&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&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="nf"&gt;isViewMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// "compact" | "comfortable"&lt;/span&gt;
  &lt;span class="nx"&gt;input&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;
  
  
  Nullish values
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&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;isNull&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isUndefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;or&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="s2"&gt;is-kit&lt;/span&gt;&lt;span class="dl"&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;const&lt;/span&gt; &lt;span class="nx"&gt;isNullish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isNull&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isUndefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Because this is a function, it can be reused directly.&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;definedItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&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;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isNullish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The current application uses the same idea for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Error branching&lt;/li&gt;
&lt;li&gt;JSON and API-derived values&lt;/li&gt;
&lt;li&gt;Filtering nullable collections&lt;/li&gt;
&lt;li&gt;Literal-value checks&lt;/li&gt;
&lt;li&gt;UI values that may be strings or other renderable values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what production usage looks like in practice.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;not one giant schema,&lt;br&gt;
but many small decisions at normal control-flow points.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  🚀 The Practical Advantages
&lt;/h2&gt;

&lt;p&gt;After using it in the application, the advantages became clearer.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Incremental adoption
&lt;/h3&gt;

&lt;p&gt;We did not need to redesign the data layer.&lt;/p&gt;

&lt;p&gt;A check like&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;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;can become&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;isString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And later, if reuse becomes useful.&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;values&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;isString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Less assertion casting
&lt;/h3&gt;

&lt;p&gt;The old error guards repeatedly used&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;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HttpClientError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The composed version narrows once, then accesses the narrowed value normally&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;isHttpClientError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  3. Shared runtime semantics
&lt;/h3&gt;

&lt;p&gt;Questions like these now have explicit answers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does “number” include &lt;code&gt;NaN&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Does this object check accept class instances?&lt;/li&gt;
&lt;li&gt;Is this field optional, nullable, or both?&lt;/li&gt;
&lt;li&gt;Are two values compared with &lt;code&gt;===&lt;/code&gt; or &lt;code&gt;Object.is&lt;/code&gt; semantics?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The benefit is not shorter syntax alone.&lt;/p&gt;

&lt;p&gt;It is fewer slightly-different answers across the codebase.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Normal TypeScript control flow
&lt;/h3&gt;

&lt;p&gt;The result is still 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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isValidationError&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="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&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;No parse result is required.&lt;/p&gt;

&lt;p&gt;No schema object has to travel through the application.&lt;/p&gt;

&lt;p&gt;That makes the guards easy to use in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;if&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;filter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;event handlers&lt;/li&gt;
&lt;li&gt;error boundaries&lt;/li&gt;
&lt;li&gt;utility functions&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  5. Small dependency surface
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; has no runtime dependencies.&lt;/p&gt;

&lt;p&gt;That does not mean it has zero bundle cost.&lt;/p&gt;

&lt;p&gt;It means introducing it does not bring a tree of transitive runtime packages with it.&lt;/p&gt;


&lt;h2&gt;
  
  
  👮 It Became a Team Rule
&lt;/h2&gt;

&lt;p&gt;One sign of real adoption is that the library moved beyond individual preference.&lt;/p&gt;

&lt;p&gt;The production repository now has a contributor rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When combining &lt;code&gt;is-kit&lt;/code&gt; guards,&lt;br&gt;
prefer &lt;code&gt;or&lt;/code&gt;, &lt;code&gt;and&lt;/code&gt;, &lt;code&gt;andAll&lt;/code&gt;, &lt;code&gt;nullish&lt;/code&gt;, and related combinators&lt;br&gt;
instead of rebuilding the same composition with native operators.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example,&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;isTextOrNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isNumberPrimitive&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;instead of,&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;isTextOrNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;isNumberPrimitive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Both can return the same boolean.&lt;/p&gt;

&lt;p&gt;But the first version is a named, reusable guard that can be passed around and composed again.&lt;/p&gt;

&lt;p&gt;This rule is also used by coding agents working in the repository.&lt;/p&gt;

&lt;p&gt;That matters because a tool is not truly adopted if every contributor, human or AI, invents a different style.&lt;/p&gt;


&lt;h2&gt;
  
  
  ✖️ What We Cannot Claim
&lt;/h2&gt;

&lt;p&gt;I want to be careful here.&lt;/p&gt;

&lt;p&gt;We did not run a controlled study showing that &lt;code&gt;is-kit&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improved runtime performance&lt;/li&gt;
&lt;li&gt;Reduced production incidents&lt;/li&gt;
&lt;li&gt;Made every validation task easier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I will not claim those things.&lt;/p&gt;

&lt;p&gt;The effects we can actually see are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeated guards were consolidated&lt;/li&gt;
&lt;li&gt;Assertion heavy checks became composable predicates&lt;/li&gt;
&lt;li&gt;Primitive semantics became centralized&lt;/li&gt;
&lt;li&gt;Application code gained reusable narrowing functions&lt;/li&gt;
&lt;li&gt;The pattern became part of the repository guidelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is primarily a &lt;strong&gt;maintainability and type-safety improvement&lt;/strong&gt;. 🏋️‍♂️&lt;/p&gt;


&lt;h2&gt;
  
  
  👀 Why Not Use a Schema Library?
&lt;/h2&gt;

&lt;p&gt;For these call sites, we did not need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rich validation error trees&lt;/li&gt;
&lt;li&gt;Data transformations&lt;/li&gt;
&lt;li&gt;A schema-first model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We needed&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Can this &lt;code&gt;unknown&lt;/code&gt; value safely enter this branch?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is exactly where a type guard fits.&lt;/p&gt;

&lt;p&gt;For forms, API contracts, or detailed validation errors, a schema library such as &lt;code&gt;Zod&lt;/code&gt; may still be the better tool.&lt;/p&gt;

&lt;p&gt;They solve different problems.&lt;/p&gt;


&lt;h2&gt;
  
  
  🎯 What 50 Stars Means to Me
&lt;/h2&gt;

&lt;p&gt;50 stars is small compared with the largest TypeScript libraries.&lt;/p&gt;

&lt;p&gt;But OSS does not become meaningful only after thousands of stars.&lt;/p&gt;

&lt;p&gt;For me, this milestone means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;People outside the project understand the idea&lt;/li&gt;
&lt;li&gt;The API is useful beyond a toy example&lt;/li&gt;
&lt;li&gt;The library is solving a real maintenance problem&lt;/li&gt;
&lt;li&gt;There is still a lot to improve&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the production application gives the milestone some weight.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; is not only being starred.&lt;/p&gt;

&lt;p&gt;It is currently helping real application code answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“What is this value, and can TypeScript trust it?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thank you to everyone who starred, tested, reported an issue, or simply looked at the repository.&lt;/p&gt;

&lt;p&gt;If small composable type guards fit your TypeScript style, give it a try 👇&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;
        is-kit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Build small guards. Compose them. Lightweight, zero-dependency TypeScript type guards for runtime validation and natural narrowing. Runtime-safe 🛡️, composable 🧩, and ergonomic ✨.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;is-kit&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/nyaomaru/is-kit/main/docs/public/iskit_image.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fis-kit%2Fmain%2Fdocs%2Fpublic%2Fiskit_image.png" width="600" alt="is-kit logo"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://www.npmjs.com/package/is-kit" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/cb829c46f855a6f184f255391ea5fe58bb6ed17112e34d4856acd61dc63179c2/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f69732d6b69742e737667" alt="npm version"&gt;
  &lt;/a&gt;
  &lt;a href="https://jsr.io/@nyaomaru/is-kit" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/b6648f6bf32eb9dff2136ce8538ccb4cc6af537c1127292b5fb0de416f7a69b4/68747470733a2f2f696d672e736869656c64732e696f2f6a73722f762f406e79616f6d6172752f69732d6b6974" alt="JSR"&gt;
  &lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/is-kit" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/9b30eeaac46ebced99b5e0dc290fd045bc34c738c66b5d95c4b6ee8fed358b34/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f64742f69732d6b69742e737667" alt="npm downloads"&gt;
  &lt;/a&gt;
  &lt;a href="https://github.com/nyaomaru/is-kit/blob/main/LICENSE" rel="noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/631cdf8c56ad84dd8657fe3371b93015b5474c517422f968ff4ec944bb28bf2f/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f6c2f69732d6b69742e7376673f73616e6974697a653d74727565" alt="License"&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Build small guards. Compose them.&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; is a lightweight, zero-dependency toolkit for building reusable TypeScript &lt;strong&gt;type guards&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It helps you write small &lt;code&gt;isFoo&lt;/code&gt; functions, compose them into &lt;strong&gt;richer runtime checks&lt;/strong&gt;, and keep &lt;strong&gt;TypeScript narrowing&lt;/strong&gt; natural inside regular control flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime-safe&lt;/strong&gt; 🛡️, &lt;strong&gt;composable&lt;/strong&gt; 🧩, and &lt;strong&gt;ergonomic&lt;/strong&gt; ✨ without asking you to adopt a heavy schema workflow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build and reuse &lt;strong&gt;typed guards&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compose guards&lt;/strong&gt; with &lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, &lt;code&gt;not&lt;/code&gt;, &lt;code&gt;oneOf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate object&lt;/strong&gt; shapes and collections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parse or assert&lt;/strong&gt; &lt;code&gt;unknown&lt;/code&gt; values without a large schema framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://is-kit.dev/" rel="nofollow noopener noreferrer"&gt;📚 Documentation Site&lt;/a&gt; ·
&lt;a href="https://is-kit.dev/guides" rel="nofollow noopener noreferrer"&gt;🧭 Practical Guides&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Best for &lt;strong&gt;app-internal narrowing, filtering, and reusable guards&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🤔 Why use &lt;code&gt;is-kit&lt;/code&gt;?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Tired of rewriting the same &lt;code&gt;isFoo&lt;/code&gt; checks again and again?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; is a good fit when you want to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;write reusable &lt;code&gt;isX&lt;/code&gt;&lt;/strong&gt; functions instead of one-off inline checks&lt;/li&gt;
&lt;li&gt;keep runtime validation &lt;strong&gt;lightweight and dependency-free&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;narrow values directly&lt;/strong&gt; in &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>typescript</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Celebrating 10,000 Total Views on DEV! 🥳 Let’s Check the Stats 😸</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 05 Aug 2026 13:54:19 +0000</pubDate>
      <link>https://dev.to/nyaomaru/celebrating-10000-total-views-on-dev-lets-check-the-stats-224e</link>
      <guid>https://dev.to/nyaomaru/celebrating-10000-total-views-on-dev-lets-check-the-stats-224e</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I'm &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who recently watched a flock of geese march through Heerlen. 🪿🪿🪿&lt;/p&gt;

&lt;p&gt;Thank you for reading my articles!&lt;/p&gt;

&lt;p&gt;My total views on DEV have now passed &lt;strong&gt;10,000&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyqri4p5vmkbs6ijml340.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyqri4p5vmkbs6ijml340.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm so happy that my articles have been read by so many developers.&lt;/p&gt;

&lt;p&gt;To celebrate this milestone, I opened my article dashboard and checked my overall stats and post rankings.&lt;/p&gt;

&lt;p&gt;Let's take a look together!&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 DEV Post Stats
&lt;/h2&gt;

&lt;p&gt;I have published &lt;strong&gt;28 posts&lt;/strong&gt; since 28 September 2025, excluding this one.&lt;/p&gt;

&lt;p&gt;Here are my overall stats:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8m00646uldrd45wb0sec.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8m00646uldrd45wb0sec.png" alt="DEV dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the average stats per article 👇&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Average&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Views&lt;/td&gt;
&lt;td&gt;387.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reactions&lt;/td&gt;
&lt;td&gt;24.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comments&lt;/td&gt;
&lt;td&gt;3.6&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I'm honestly surprised by these results!&lt;/p&gt;

&lt;p&gt;I'll continue publishing more interesting posts. 💪&lt;/p&gt;




&lt;h2&gt;
  
  
  👑 Post Rankings
&lt;/h2&gt;

&lt;p&gt;In this article, I'll introduce my top posts in the following categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most Reactions&lt;/li&gt;
&lt;li&gt;Most Comments&lt;/li&gt;
&lt;li&gt;Most Views&lt;/li&gt;
&lt;li&gt;My Personal Recommendations&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💖 Most Reactions
&lt;/h2&gt;

&lt;p&gt;The article with the most reactions is...&lt;/p&gt;

&lt;p&gt;Drrrrrr... 🥁&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Which OpenAPI Codegen Should You Choose? openapi-typescript vs Hey API vs Orval vs Kubb&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/which-openapi-codegen-should-you-choose-openapi-typescript-vs-hey-api-vs-orval-vs-kubb-100p" class="crayons-story__hidden-navigation-link"&gt;Which OpenAPI Codegen Should You Choose? openapi-typescript vs hey-api vs Orval vs Kubb&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-3688298" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/which-openapi-codegen-should-you-choose-openapi-typescript-vs-hey-api-vs-orval-vs-kubb-100p" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 20&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/which-openapi-codegen-should-you-choose-openapi-typescript-vs-hey-api-vs-orval-vs-kubb-100p" id="article-link-3688298"&gt;
          Which OpenAPI Codegen Should You Choose? openapi-typescript vs hey-api vs Orval vs Kubb
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/openapi"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;openapi&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/frontend"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;frontend&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/which-openapi-codegen-should-you-choose-openapi-typescript-vs-hey-api-vs-orval-vs-kubb-100p" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;60&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/which-openapi-codegen-should-you-choose-openapi-typescript-vs-hey-api-vs-orval-vs-kubb-100p#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              15&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            18 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;It received &lt;strong&gt;60 reactions&lt;/strong&gt;!! Thank you very very much. 🙏&lt;/p&gt;

&lt;p&gt;I'm especially proud of this result because this was the article I worked hardest on.&lt;/p&gt;

&lt;p&gt;I tested each library against a large production codebase, and we actually adopted Hey API in our system's CI pipeline.&lt;/p&gt;

&lt;p&gt;I also recently tried generating Faker data and mocks with Hey API, and both features were excellent.&lt;/p&gt;

&lt;p&gt;After that, I evaluated the libraries again. What interested me most was the impressive performance of Kubb v5, which is currently in beta.&lt;/p&gt;

&lt;p&gt;In my test, Kubb v5 was more than &lt;strong&gt;five times faster&lt;/strong&gt; than v4!&lt;/p&gt;

&lt;p&gt;That is some amazing performance tuning.&lt;/p&gt;

&lt;p&gt;We should keep an eye on how OpenAPI code generators continue to evolve.&lt;/p&gt;




&lt;h2&gt;
  
  
  💬 Most Comments
&lt;/h2&gt;

&lt;p&gt;The article with the most comments is...&lt;/p&gt;

&lt;p&gt;Drrrrrr... 🥁&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__hidden-navigation-link"&gt;I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Features a timeline to step backward mid-loop&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4143027" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 15&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" id="article-link-4143027"&gt;
          I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;64&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              33&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;It received &lt;strong&gt;21 comments&lt;/strong&gt;!! Thank you very much. 🙏&lt;/p&gt;

&lt;p&gt;I recently released &lt;strong&gt;DSA View View&lt;/strong&gt;, and this article introduces the project.&lt;/p&gt;

&lt;p&gt;It is still brand new, so please take a look!&lt;/p&gt;

&lt;p&gt;If you want to improve your software engineering skills, DSA View View may help you understand data structures and algorithms more clearly.&lt;/p&gt;

&lt;p&gt;The article covers questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why do we still need to learn DSA in the AI era?&lt;/li&gt;
&lt;li&gt;How can you use DSA View View?&lt;/li&gt;
&lt;li&gt;What should you study first?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the answers in the article.&lt;/p&gt;




&lt;h2&gt;
  
  
  👀 Most Views
&lt;/h2&gt;

&lt;p&gt;The article with the most views is...&lt;/p&gt;

&lt;p&gt;Drrrrrr... 🥁&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Let’s Learn Feature-Sliced Design (FSD)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/lets-learn-feature-sliced-design-fsd-15bb" class="crayons-story__hidden-navigation-link"&gt;Let’s Learn Feature-Sliced Design (FSD)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-2872478" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/lets-learn-feature-sliced-design-fsd-15bb" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Sep 28 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/lets-learn-feature-sliced-design-fsd-15bb" id="article-link-2872478"&gt;
          Let’s Learn Feature-Sliced Design (FSD)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/architecture"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;architecture&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/design"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;design&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/frontend"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;frontend&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/lets-learn-feature-sliced-design-fsd-15bb" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;9&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/lets-learn-feature-sliced-design-fsd-15bb#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;It has received more than &lt;strong&gt;1,900 views&lt;/strong&gt;! Thank you very much. 🙏&lt;/p&gt;

&lt;p&gt;Because this was my first post on DEV, simply being online longer may have helped it reach this number.&lt;/p&gt;

&lt;p&gt;However, I also think Feature-Sliced Design can be a useful architecture for AI-assisted development.&lt;/p&gt;

&lt;p&gt;The clear separation between layers, slices, and segments can make a codebase easier to understand and maintain.&lt;/p&gt;

&lt;p&gt;Of course, learning FSD requires some time and effort. However, AI tools can learn this structure, and humans can follow it too.&lt;/p&gt;

&lt;p&gt;If you are struggling to maintain a legacy codebase, FSD may be worth trying.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⭐ My Personal Recommendations
&lt;/h2&gt;

&lt;p&gt;This is a special section containing some of my personal favourite articles.&lt;/p&gt;

&lt;p&gt;One of my recommendations is...&lt;/p&gt;

&lt;p&gt;Drrrrrr... 🥁&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🧠 Understanding Variance in TypeScript &amp;amp; Flow: Covariant, Contravariant, Invariant, Bivariant&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/understanding-variance-in-typescript-flow-covariant-contravariant-invariant-bivariant-4fbi" class="crayons-story__hidden-navigation-link"&gt;🧠 Understanding Variance in TypeScript &amp;amp; Flow: Covariant, Contravariant, Invariant, Bivariant&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-3059743" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/understanding-variance-in-typescript-flow-covariant-contravariant-invariant-bivariant-4fbi" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 26 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/understanding-variance-in-typescript-flow-covariant-contravariant-invariant-bivariant-4fbi" id="article-link-3059743"&gt;
          🧠 Understanding Variance in TypeScript &amp;amp; Flow: Covariant, Contravariant, Invariant, Bivariant
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/beginners"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;beginners&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/understanding-variance-in-typescript-flow-covariant-contravariant-invariant-bivariant-4fbi" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;40&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/understanding-variance-in-typescript-flow-covariant-contravariant-invariant-bivariant-4fbi#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              6&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            10 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;In this article, I tried to explain variance in TypeScript.&lt;/p&gt;

&lt;p&gt;I often forget the differences myself, so I wrote this article as a reference—and I still go back and read it. 😸&lt;/p&gt;

&lt;p&gt;If you are struggling to understand variance in TypeScript, please check it out!&lt;/p&gt;

&lt;p&gt;And here is one more recommendation.&lt;/p&gt;

&lt;p&gt;Drrrrrr... 🥁&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;is-kit vs Zod: A Practical Comparison from 3 Perspectives&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/is-kit-vs-zod-a-practical-comparison-from-3-perspectives-21eh" class="crayons-story__hidden-navigation-link"&gt;is-kit vs Zod: A Practical Comparison from 3 Perspectives&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-3522623" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/is-kit-vs-zod-a-practical-comparison-from-3-perspectives-21eh" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 22&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/is-kit-vs-zod-a-practical-comparison-from-3-perspectives-21eh" id="article-link-3522623"&gt;
          is-kit vs Zod: A Practical Comparison from 3 Perspectives
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/productivity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;productivity&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/is-kit-vs-zod-a-practical-comparison-from-3-perspectives-21eh" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;42&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/is-kit-vs-zod-a-practical-comparison-from-3-perspectives-21eh#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              7&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;What is &lt;strong&gt;is-kit&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;If that is what you are thinking, please read the article!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; is a lightweight and simple type guard kit.&lt;/p&gt;

&lt;p&gt;If you want an easy way to protect your code from unknown values, you may enjoy using &lt;code&gt;is-kit&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Summary
&lt;/h2&gt;

&lt;p&gt;I'm really happy to publish this celebration article.&lt;/p&gt;

&lt;p&gt;My next milestone is &lt;strong&gt;30,000 total views&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;I'll continue publishing interesting articles about frontend development, TypeScript, architecture, developer tools, and my own projects.&lt;/p&gt;

&lt;p&gt;If any of these articles caught your attention, please take a look.&lt;/p&gt;

&lt;p&gt;I hope at least one of them helps you!&lt;/p&gt;

&lt;p&gt;See you in the next article!&lt;/p&gt;

</description>
      <category>devto</category>
      <category>writing</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>How I Made JavaScript Execution Visual and Rewindable (DSA View View 👀👀)</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 29 Jul 2026 10:42:13 +0000</pubDate>
      <link>https://dev.to/nyaomaru/how-i-made-javascript-execution-visual-and-rewindable-dsa-view-view--42k4</link>
      <guid>https://dev.to/nyaomaru/how-i-made-javascript-execution-visual-and-rewindable-dsa-view-view--42k4</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I'm &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who was recently &lt;strong&gt;knocked off my feet by how good the zeetong (sole) from a Dutch fish shop was&lt;/strong&gt;. 🐟😸&lt;/p&gt;

&lt;p&gt;In the previous article, I explained how DSA View View takes the &lt;code&gt;TypeScript&lt;/code&gt; written by a user, analyzes the function or class signature, and generates a Verification form.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/how-i-built-the-editor-and-compile-pipeline-for-a-typescript-dsa-visualizer-dsa-view-view--530f" class="crayons-story__hidden-navigation-link"&gt;How I Built the Editor and Compile Pipeline for a TypeScript DSA Visualizer (DSA View View 👀👀)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4197911" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/how-i-built-the-editor-and-compile-pipeline-for-a-typescript-dsa-visualizer-dsa-view-view--530f" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 22&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/how-i-built-the-editor-and-compile-pipeline-for-a-typescript-dsa-visualizer-dsa-view-view--530f" id="article-link-4197911"&gt;
          How I Built the Editor and Compile Pipeline for a TypeScript DSA Visualizer (DSA View View 👀👀)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/how-i-built-the-editor-and-compile-pipeline-for-a-typescript-dsa-visualizer-dsa-view-view--530f" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;35&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/how-i-built-the-editor-and-compile-pipeline-for-a-typescript-dsa-visualizer-dsa-view-view--530f#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            10 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;This time, we are entering the heart of DSA View View: the &lt;strong&gt;Runtime&lt;/strong&gt; and &lt;strong&gt;Visualization&lt;/strong&gt; layers.&lt;/p&gt;

&lt;p&gt;If you call an ordinary JavaScript function, the direct result you get back is usually the final return value.&lt;/p&gt;

&lt;p&gt;But when I am studying DSA, that is not the part I really want to see.&lt;/p&gt;

&lt;p&gt;I want to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happened in the middle of the loop?&lt;/li&gt;
&lt;li&gt;When did the pointer move?&lt;/li&gt;
&lt;li&gt;At which exact moment did the variable change?&lt;/li&gt;
&lt;li&gt;How deep did the recursion go?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, I want to see &lt;strong&gt;the journey to the answer&lt;/strong&gt;, not only the answer itself.&lt;/p&gt;

&lt;p&gt;JavaScript, unfortunately, does not provide an API that accepts:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Excuse me, could you move the current line one step backward?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So how does DSA View View rewind execution?&lt;/p&gt;

&lt;p&gt;Here is the answer up front. 😸&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before execution, DSA View View rewrites the code into a version that can record its intermediate state, then runs it until it completes or reaches a configured limit.&lt;/p&gt;

&lt;p&gt;The UI then plays those recorded states forward and backward like security-camera footage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article, we will look at that &lt;strong&gt;record-and-replay&lt;/strong&gt; system through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AST transformation with Babel&lt;/li&gt;
&lt;li&gt;Injecting &lt;code&gt;recordStep&lt;/code&gt; calls&lt;/li&gt;
&lt;li&gt;Preserving the original meaning of the code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ExecutionStep&lt;/code&gt; and snapshot patches&lt;/li&gt;
&lt;li&gt;Rewinding and jumping to variable changes&lt;/li&gt;
&lt;li&gt;Running code inside a Web Worker&lt;/li&gt;
&lt;li&gt;Detecting the appropriate Visualization&lt;/li&gt;
&lt;li&gt;Tests that protect the AST transformation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The source code is available here 👇&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;
        dsa-view-view
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DSA View View allows you to understand DSA to see the data flow. 👀👀 Of course, it's free.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nyaomaru/dsa-view-view/./public/readme-view-view.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Freadme-view-view.png" alt="DSA View View" width="100%"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DSA View View&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;DSA View View turns TypeScript algorithm functions into step-by-step visual
stories. 👀👀&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-tv.gif" alt="DSA View View TV"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Write code, run it with structured inputs, and see the arrays, matrices
trees, lists, stacks, pointers, and return values move as the function executes.&lt;/p&gt;
&lt;p&gt;It is built for those moments when reading the code is not enough and you want
to &lt;em&gt;view&lt;/em&gt; why the answer changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-demo.gif" alt="DSA View View demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Try It?&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🧠 &lt;strong&gt;Step through real TypeScript&lt;/strong&gt;&lt;br&gt;
Paste or edit a function, validate it, then run the exact code in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🧩 &lt;strong&gt;Views that match the data&lt;/strong&gt;&lt;br&gt;
Arrays become bars, matrices become grids, trees become node graphs, linked lists become chains, and two-pointer area problems get their own visual view.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🌳 &lt;strong&gt;DSA-friendly inputs out of the box&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;TreeNode&lt;/code&gt;, &lt;code&gt;ListNode&lt;/code&gt;, &lt;code&gt;MinHeap&lt;/code&gt;, &lt;code&gt;MaxHeap&lt;/code&gt;, &lt;code&gt;PriorityQueue&lt;/code&gt;, nested arrays
matrices, strings, numbers, and class-style inputs are supported without
ceremony.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔎 &lt;strong&gt;39 built-in examples&lt;/strong&gt;&lt;br&gt;
Search by name, browse…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;All right, let’s open the Runtime and see what Mr. View has been watching. 👀👀&lt;/p&gt;




&lt;h2&gt;
  
  
  📝 The Big Picture: Turning Execution into an Array of Steps
&lt;/h2&gt;

&lt;p&gt;The Runtime pipeline looks roughly 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;User TypeScript
      ↓
Prepare common DSA classes
      ↓
Parse the code into an AST with Babel Parser
      ↓
Visitors inject recordStep(...)
      ↓
Transform TypeScript into JavaScript with Babel
      ↓
Execute it with new Function inside a Web Worker
      ↓
Generate ExecutionStep[]
      ↓
React moves currentStep forward and backward
      ↓
Display the Visualization that matches the trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important design decision here is that &lt;strong&gt;the user’s code is not connected directly to a React component&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead, &lt;code&gt;ExecutionStep[]&lt;/code&gt; acts as a shared recording format.&lt;/p&gt;

&lt;p&gt;That lets arrays, pointers, recursion, trees, heaps, and other structures all live on the same timeline.&lt;/p&gt;

&lt;p&gt;Let’s walk through how that works.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔭 Runtime: Planting Observation Points in the Code
&lt;/h2&gt;

&lt;p&gt;This is the heart of DSA View View. 💖&lt;/p&gt;

&lt;p&gt;The Runtime needs intermediate states, so it does not execute the user’s code exactly as written.&lt;/p&gt;

&lt;p&gt;First, Babel transforms the AST and injects calls to &lt;code&gt;recordStep&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Injecting &lt;code&gt;recordStep&lt;/code&gt; into the AST
&lt;/h3&gt;

&lt;p&gt;Suppose the user writes.&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;let&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&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;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&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;DSA View View parses it into an AST and transforms it into something roughly 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;let&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;recordStep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;variable-declaration&lt;/span&gt;&lt;span class="dl"&gt;"&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;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;let left = 0&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;left&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;recordStep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loop-iteration&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;while (left &amp;lt; right)&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;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;recordStep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assignment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left++&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;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&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;The second argument to &lt;code&gt;recordStep&lt;/code&gt; is the original source line number, not the execution-step number.&lt;br&gt;
Because line 2 is empty, the recorded lines are &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, and &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the real implementation, dedicated visitors handle AST nodes such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FunctionDeclaration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FunctionExpression&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ArrowFunctionExpression&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ClassMethod&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VariableDeclaration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AssignmentExpression&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UpdateExpression&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CallExpression&lt;/code&gt; nodes that mutate arrays&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;for&lt;/code&gt; / &lt;code&gt;while&lt;/code&gt; / &lt;code&gt;for...of&lt;/code&gt; / &lt;code&gt;for...in&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ReturnStatement&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A step can therefore be recorded when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A function is entered&lt;/li&gt;
&lt;li&gt;A variable is declared&lt;/li&gt;
&lt;li&gt;A loop completes an iteration&lt;/li&gt;
&lt;li&gt;A value is assigned&lt;/li&gt;
&lt;li&gt;An array is mutated&lt;/li&gt;
&lt;li&gt;A function returns&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Current limitation&lt;/strong&gt;&lt;br&gt;
callback bodies inside methods such as &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and &lt;code&gt;forEach&lt;/code&gt; are intentionally excluded from instrumentation for now.&lt;/p&gt;

&lt;p&gt;The goal is not to trace every corner of JavaScript immediately. I am starting with patterns that are useful for DSA traces and can be instrumented without breaking the original behavior.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Injecting the Code Is Easier Than Not Breaking It
&lt;/h3&gt;

&lt;p&gt;The hardest part of the AST transformation was not calling &lt;code&gt;recordStep&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The hard part was making sure that,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;after adding the recording logic, every original expression is still evaluated the same number of times and still returns the same value.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, if a return expression were evaluated once for recording and once for the actual return, its side effects would run twice.&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;return&lt;/span&gt; &lt;span class="nf"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the transformed code first stores the value in a temporary variable.&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;algorithmVisualizerReturnValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;recordStep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;return&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;return value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;algorithmVisualizerReturnValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;return location&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;returnLocation&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;algorithmVisualizerReturnValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assignment expressions are another fun little trap.&lt;/p&gt;

&lt;p&gt;Consider 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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The transformed code must preserve all three facts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;i++&lt;/code&gt; runs exactly once&lt;/li&gt;
&lt;li&gt;The pre-increment value of &lt;code&gt;i&lt;/code&gt; is used as the array index&lt;/li&gt;
&lt;li&gt;The assignment expression itself evaluates to &lt;code&gt;7&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DSA View View wraps the assignment in a synthetic arrow function, stores the result in a temporary variable, records the step, and returns the same value.&lt;/p&gt;

&lt;p&gt;Using an arrow function also avoids accidentally stealing the surrounding &lt;code&gt;this&lt;/code&gt; or &lt;code&gt;arguments&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;AST transformation cannot be "close enough".&lt;/p&gt;

&lt;p&gt;If adding more visible steps changes the answer, the visualizer has somehow become the least trustworthy character in the story.&lt;/p&gt;

&lt;p&gt;Not ideal.&lt;/p&gt;




&lt;h2&gt;
  
  
  🖍️ &lt;code&gt;ExecutionStep&lt;/code&gt;: Making Execution Replayable
&lt;/h2&gt;

&lt;p&gt;The Runtime records each observed state as an &lt;code&gt;ExecutionStep&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A shortened version of the real type looks 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;type&lt;/span&gt; &lt;span class="nx"&gt;ExecutionStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;stepNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionStepType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;column&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;description&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="nl"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;callStack&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="nl"&gt;scope&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="nl"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;loopIteration&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;conditionResult&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;functionName&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="nl"&gt;heapTrace&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;HeapTraceSnapshot&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;The Runtime currently generates steps including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;function-call&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;function-entry&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;variable-declaration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assignment&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;array-mutation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;loop-iteration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;return&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;line&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; are used in the timeline.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;variables&lt;/code&gt; provides the data needed to reconstruct the UI at that moment.&lt;/p&gt;

&lt;p&gt;Recursive traces also use &lt;code&gt;callStack&lt;/code&gt;, while prepared heap implementations can attach &lt;code&gt;metadata.heapTrace&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Saving References Would Rewrite the Past
&lt;/h3&gt;

&lt;p&gt;Suppose an array reference were stored directly inside a step.&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;stack&lt;/span&gt; &lt;span class="o"&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nf"&gt;recordStep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* save stack */&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the recorded step keeps the same reference, the earlier state will also appear as &lt;code&gt;[0]&lt;/code&gt; after &lt;code&gt;pop()&lt;/code&gt; runs.&lt;/p&gt;

&lt;p&gt;That is not a historical record.&lt;/p&gt;

&lt;p&gt;That is the past quietly editing itself.&lt;/p&gt;

&lt;p&gt;So values passed to &lt;code&gt;recordStep&lt;/code&gt; are deep-cloned at that moment.&lt;/p&gt;

&lt;p&gt;The Runtime normally uses &lt;code&gt;structuredClone&lt;/code&gt;. When it encounters values that need different handling, it falls back to a cloning implementation that supports cycles, &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt;, &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;RegExp&lt;/code&gt;, and other cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Delta Snapshot" Is Really More Like a Patch
&lt;/h3&gt;

&lt;p&gt;The implementation contains a name called &lt;code&gt;variableDeltas&lt;/code&gt;, but this deserves a more precise explanation.&lt;/p&gt;

&lt;p&gt;The current Runtime does &lt;strong&gt;not&lt;/strong&gt; compare every value with the previous state and store only the keys that truly changed.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first step stores the initial state, including the inputs&lt;/li&gt;
&lt;li&gt;Later steps deep-clone the visible variables passed to that &lt;code&gt;recordStep&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;When a full snapshot is needed, the patches are merged in order&lt;/li&gt;
&lt;li&gt;Reconstructed snapshots are cached&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, strictly speaking, these are closer to &lt;strong&gt;per-step patches&lt;/strong&gt; than minimal deltas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 0 patch: { left: 0, right: 5 }
Step 1 patch: { left: 1 }
Step 2 patch: { right: 4 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reconstructing them produces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 0 snapshot: { left: 0, right: 5 }
Step 1 snapshot: { left: 1, right: 5 }
Step 2 snapshot: { left: 1, right: 4 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;variables&lt;/code&gt; property of each &lt;code&gt;ExecutionStep&lt;/code&gt; is a getter.&lt;/p&gt;

&lt;p&gt;It starts from a previously cached snapshot and merges only the patches needed to reach the requested step.&lt;/p&gt;

&lt;p&gt;There is one more implementation detail worth mentioning.&lt;/p&gt;

&lt;p&gt;The Runtime sends state from the Worker to the UI with &lt;code&gt;postMessage&lt;/code&gt;. During that structured clone, reading the getter also materializes the snapshot.&lt;/p&gt;

&lt;p&gt;So the data does not remain a tiny delta forever and magically arrive on the main thread in that form.&lt;/p&gt;

&lt;p&gt;The design mainly reduces eager reconstruction and cloning &lt;strong&gt;while the execution is being recorded&lt;/strong&gt;. 📽️&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Can the Timeline Move Backward?
&lt;/h3&gt;

&lt;p&gt;DSA View View is &lt;strong&gt;not reversing JavaScript while it runs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Inside the Web Worker, it first rewrites the code into an instrumented version and records the execution.&lt;/p&gt;

&lt;p&gt;During playback, the main value that changes is &lt;code&gt;currentStep&lt;/code&gt;.&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;type&lt;/span&gt; &lt;span class="nx"&gt;ExecutionState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;currentStep&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;totalSteps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionStep&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;isComplete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;returnValue&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moving forward displays the snapshot for &lt;code&gt;currentStep + 1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Moving backward displays the snapshot for &lt;code&gt;currentStep - 1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So rewinding means,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;selecting an earlier recorded frame, not undoing the execution itself&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once recording has finished, users can navigate without rerunning their code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pause&lt;/li&gt;
&lt;li&gt;Move one step forward or backward&lt;/li&gt;
&lt;li&gt;Jump to any step in the timeline&lt;/li&gt;
&lt;li&gt;Move to the first or final step&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Users can also select a variable and jump directly to the previous step where its value changed.&lt;/p&gt;

&lt;p&gt;That is especially useful for pointers such as &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;left&lt;/code&gt;, and &lt;code&gt;right&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No more clicking the Back button 47 times while whispering, "Where did you go wrong?" 😸&lt;/p&gt;

&lt;h3&gt;
  
  
  There Is a Generator, but It Does Not Suspend the User’s Code Line by Line
&lt;/h3&gt;

&lt;p&gt;The Runtime API contains a &lt;code&gt;Generator&amp;lt;ExecutionStep, ...&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That might make it look as if the user’s code itself is being paused line by line with &lt;code&gt;yield&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is not.&lt;/p&gt;

&lt;p&gt;After yielding the first &lt;code&gt;function-call&lt;/code&gt; step, the instrumented code runs once and accumulates steps inside the execution context.&lt;/p&gt;

&lt;p&gt;The generator then yields the already-recorded steps in order.&lt;/p&gt;

&lt;p&gt;In the path used by the UI, the Worker consumes the generator completely and returns the finished &lt;code&gt;ExecutionState&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Separating &lt;strong&gt;execution&lt;/strong&gt; from &lt;strong&gt;playback&lt;/strong&gt; is what makes the rewind behavior relatively simple.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Web Worker: Do Not Take the UI Down with You
&lt;/h2&gt;

&lt;p&gt;User code runs inside a dedicated Web Worker instead of the main thread.&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;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&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;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./execution-worker.ts&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;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;algorithm-execution&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;An infinite loop or expensive computation on the main thread would freeze the entire page.&lt;/p&gt;

&lt;p&gt;By moving execution into a Worker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The React UI stays on the main thread&lt;/li&gt;
&lt;li&gt;Starting a new run or leaving the page can terminate the Worker through an &lt;code&gt;AbortController&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Runtime also has limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execution timeout: 10 seconds&lt;/li&gt;
&lt;li&gt;Maximum recorded steps: 3,000&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a limit is reached, the Worker can be terminated or execution can stop early with a warning.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Worker Is Not a Security Sandbox
&lt;/h3&gt;

&lt;p&gt;A Web Worker does not have access to the page DOM, &lt;code&gt;localStorage&lt;/code&gt;, or &lt;code&gt;sessionStorage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;DSA View View also does not execute user code on a server.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;a Web Worker is not a security boundary that makes untrusted code safe.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The user code runs through &lt;code&gt;new Function&lt;/code&gt; in the Worker global scope.&lt;/p&gt;

&lt;p&gt;Web APIs available inside Workers, including &lt;code&gt;fetch&lt;/code&gt;, are not automatically disabled.&lt;/p&gt;

&lt;p&gt;The purpose of this architecture is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolate heavy execution from the main thread&lt;/li&gt;
&lt;li&gt;Terminate an execution unit on timeout or cancellation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is an execution boundary for responsiveness and control, not a magical prison for JavaScript.&lt;/p&gt;

&lt;p&gt;JavaScript has watched enough escape-room videos to know better.&lt;/p&gt;




&lt;h2&gt;
  
  
  👀 Visualization: Variables Alone Are Not Enough
&lt;/h2&gt;

&lt;p&gt;The Runtime returns an &lt;code&gt;ExecutionState&lt;/code&gt; and snapshots for each step.&lt;/p&gt;

&lt;p&gt;The next problem is deciding which View should display that trace.&lt;/p&gt;

&lt;p&gt;DSA View View does not ask AI,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey, does this look like Binary Search?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;on every run.&lt;/p&gt;

&lt;p&gt;Instead, visualization candidates are detected through logic based on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Variable names&lt;/li&gt;
&lt;li&gt;Variable types and data structures&lt;/li&gt;
&lt;li&gt;Whether arrays or matrices actually changed&lt;/li&gt;
&lt;li&gt;Pointers such as &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;, and &lt;code&gt;mid&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The call stack&lt;/li&gt;
&lt;li&gt;Function-entry and return history&lt;/li&gt;
&lt;li&gt;Heap metadata&lt;/li&gt;
&lt;li&gt;Changes across multiple steps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, displaying a Sort Graph whenever a &lt;code&gt;number[]&lt;/code&gt; exists would classify algorithms that only &lt;em&gt;read&lt;/em&gt; an input array as sorting algorithms.&lt;/p&gt;

&lt;p&gt;So the detection logic checks whether the numeric array actually changes between steps.&lt;/p&gt;

&lt;p&gt;It also looks for context such as &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;swap&lt;/code&gt;, &lt;code&gt;partition&lt;/code&gt;, and &lt;code&gt;pivot&lt;/code&gt; in descriptions or the call stack.&lt;/p&gt;

&lt;p&gt;Some representative mappings are 👇&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Runtime state&lt;/th&gt;
&lt;th&gt;Displayed View&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A changing numeric array&lt;/td&gt;
&lt;td&gt;Sort Graph&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An array used as a stack&lt;/td&gt;
&lt;td&gt;Stack View&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search using &lt;code&gt;left&lt;/code&gt; / &lt;code&gt;right&lt;/code&gt; / &lt;code&gt;mid&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Index View&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sliding Window pointers&lt;/td&gt;
&lt;td&gt;Sliding Window View&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A two-dimensional array&lt;/td&gt;
&lt;td&gt;Matrix View&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DP arrays or rolling state&lt;/td&gt;
&lt;td&gt;DP View&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TreeNode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tree Graph&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ListNode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List Graph&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recursive function entry and return&lt;/td&gt;
&lt;td&gt;Recursion Tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logic using &lt;code&gt;Map&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Map View&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logic using both &lt;code&gt;MinHeap&lt;/code&gt; and &lt;code&gt;MaxHeap&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Heap View&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Word Ladder-style BFS&lt;/td&gt;
&lt;td&gt;Word Ladder View&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Container / rain-water / histogram pointers&lt;/td&gt;
&lt;td&gt;Area View&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Calculator character positions and sign stack&lt;/td&gt;
&lt;td&gt;Expression View&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When multiple candidate Views are found, DSA View View assigns priorities and selects a primary Visualization.&lt;/p&gt;

&lt;p&gt;For example, if heap state is available, Heap View takes priority over an ordinary array View.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visualization Is Built from &lt;code&gt;ExecutionState&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Each Visualizer knows nothing about the user’s source code.&lt;/p&gt;

&lt;p&gt;It extracts what it needs from the current &lt;code&gt;ExecutionState&lt;/code&gt; and converts that data into View-specific state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BinarySearchVisualizer&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;indexState&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;currentStep&lt;/code&gt; changes, the same Visualizer receives a new state.&lt;/p&gt;

&lt;p&gt;CSS transitions and Framer Motion animate the difference, making pointers and nodes appear to move.&lt;/p&gt;

&lt;p&gt;This creates a clean separation of responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runtime creates a correct trace while preserving the original behavior&lt;/li&gt;
&lt;li&gt;Detection decides which View best represents the trace&lt;/li&gt;
&lt;li&gt;Visualization focuses on how to display that state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adding a new visualization generally follows this path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Detect the target execution state&lt;/li&gt;
&lt;li&gt;Convert it into View-specific state&lt;/li&gt;
&lt;li&gt;Render it with a React component&lt;/li&gt;
&lt;li&gt;Add it to the primary-visualization selection&lt;/li&gt;
&lt;li&gt;Add the smallest reproducible code sample as a test&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🧪 Tests: Reducing the Number of "It Happened to Work" Cases
&lt;/h2&gt;

&lt;p&gt;Users can write code freely, which means they can also write it in ways I never expected.&lt;/p&gt;

&lt;p&gt;AST transformations are especially dangerous because fixing one syntax pattern can quietly break another.&lt;/p&gt;

&lt;p&gt;So when a real issue appears, I keep the smallest version of that code as a regression test.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arguments and local variables for each recursive call&lt;/li&gt;
&lt;li&gt;Postfix &lt;code&gt;i++&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;XOR assignment&lt;/li&gt;
&lt;li&gt;Nested array mutations&lt;/li&gt;
&lt;li&gt;Class constructors and &lt;code&gt;super()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TreeNode&lt;/code&gt; / &lt;code&gt;ListNode&lt;/code&gt; inputs&lt;/li&gt;
&lt;li&gt;Heap operations&lt;/li&gt;
&lt;li&gt;Binary Search and Sliding Window pointers&lt;/li&gt;
&lt;li&gt;Word Ladder BFS state&lt;/li&gt;
&lt;li&gt;Worker timeouts and step limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Trusting human memory to say,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Surely this syntax still works."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;is not a particularly strong testing strategy.&lt;/p&gt;

&lt;p&gt;Memory is surprisingly optimistic.&lt;/p&gt;

&lt;p&gt;And it would be a little embarrassing to build a tool for avoiding confusion in DSA, only to get lost inside the tool’s own behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Summary
&lt;/h2&gt;

&lt;p&gt;DSA View View is not simply turning an array into a bar chart.&lt;/p&gt;

&lt;p&gt;At a high level, it works like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write TypeScript in Monaco&lt;/li&gt;
&lt;li&gt;Analyze the source code and signature with Babel&lt;/li&gt;
&lt;li&gt;Inject &lt;code&gt;recordStep&lt;/code&gt; into the AST&lt;/li&gt;
&lt;li&gt;Execute the code inside a Web Worker&lt;/li&gt;
&lt;li&gt;Record variable snapshots and the call stack&lt;/li&gt;
&lt;li&gt;Replay the steps with React&lt;/li&gt;
&lt;li&gt;Display a View matching the data structure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The most important step was converting the user’s code into an array of &lt;code&gt;ExecutionStep&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;Once execution becomes a sequence of steps, the same &lt;code&gt;ExecutionState&lt;/code&gt; can power:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pause&lt;/li&gt;
&lt;li&gt;Forward and backward navigation&lt;/li&gt;
&lt;li&gt;Timeline jumps&lt;/li&gt;
&lt;li&gt;Navigation to the previous variable change&lt;/li&gt;
&lt;li&gt;Reconstruction of recursion trees&lt;/li&gt;
&lt;li&gt;Data-structure visualizations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key idea is "Do not try to reverse JavaScript itself. First, transform execution into a recordable domain model".&lt;/p&gt;

&lt;p&gt;Then,&lt;/p&gt;

&lt;p&gt;"Runtime focuses on producing a correct trace, while Visualization focuses on presenting that trace."&lt;/p&gt;

&lt;p&gt;Keeping Editor, Runtime, and Visualization independent from one another has been essential to making the tool extensible. Stable models such as &lt;code&gt;ExecutionStep&lt;/code&gt; and &lt;code&gt;ExecutionState&lt;/code&gt; connect these layers without coupling them directly.&lt;/p&gt;

&lt;p&gt;There are still unsupported algorithms and syntax patterns, so I would love to hear from you if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An implementation does not run&lt;/li&gt;
&lt;li&gt;You want another data structure visualized&lt;/li&gt;
&lt;li&gt;You think a trace would be clearer in a different View&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Issues and PRs are always welcome 👇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;https://github.com/nyaomaru/dsa-view-view&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s run our code and watch what it is doing inside together. 👀👀&lt;/p&gt;

&lt;p&gt;And if you enjoy the project, I would be very happy if you left a GitHub ⭐!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How I Built the Editor and Compile Pipeline for a TypeScript DSA Visualizer (DSA View View 👀👀)</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 22 Jul 2026 14:06:50 +0000</pubDate>
      <link>https://dev.to/nyaomaru/how-i-built-the-editor-and-compile-pipeline-for-a-typescript-dsa-visualizer-dsa-view-view--530f</link>
      <guid>https://dev.to/nyaomaru/how-i-built-the-editor-and-compile-pipeline-for-a-typescript-dsa-visualizer-dsa-view-view--530f</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I'm &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer. Thanks to my daily Duolingo streak, Dutch is finally starting to sound slightly less like one extremely long word. Progress! 🦉&lt;/p&gt;

&lt;p&gt;In my previous article, I introduced &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;&lt;strong&gt;DSA View View&lt;/strong&gt;&lt;/a&gt;, a tool for visualizing data structures and algorithm execution.&lt;/p&gt;

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


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__hidden-navigation-link"&gt;I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Features a timeline to step backward mid-loop&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-4143027" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 15&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" id="article-link-4143027"&gt;
          I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dsa"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dsa&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;64&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              33&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;That article covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why I decided to study DSA again&lt;/li&gt;
&lt;li&gt;What DSA View View is&lt;/li&gt;
&lt;li&gt;How to use it&lt;/li&gt;
&lt;li&gt;How I plan to study with it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if this is your first time meeting &lt;strong&gt;Mr. View&lt;/strong&gt;, the previous article is a good place to start.&lt;/p&gt;

&lt;p&gt;This time, we're opening the hood.&lt;/p&gt;

&lt;p&gt;This is the first half of the implementation story, covering everything from the moment a user writes &lt;code&gt;TypeScript&lt;/code&gt; to the moment &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;DSA View View&lt;/a&gt; generates an input form for that implementation.&lt;/p&gt;

&lt;p&gt;We'll mainly look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The overall architecture and FSD&lt;/li&gt;
&lt;li&gt;Runtime type guards with &lt;a href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;&lt;code&gt;is-kit&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Monaco&lt;/code&gt; Editor&lt;/li&gt;
&lt;li&gt;Static &lt;code&gt;TypeScript&lt;/code&gt; analysis&lt;/li&gt;
&lt;li&gt;Compilation with &lt;code&gt;Babel&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Extracting function signatures from the AST&lt;/li&gt;
&lt;li&gt;Generating the Verification form&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the source code here:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;
        dsa-view-view
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DSA View View allows you to understand DSA to see the data flow. 👀👀 Of course, it's free.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nyaomaru/dsa-view-view/./public/readme-view-view.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Freadme-view-view.png" alt="DSA View View" width="100%"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DSA View View&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;DSA View View turns TypeScript algorithm functions into step-by-step visual
stories. 👀👀&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-tv.gif" alt="DSA View View TV"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Write code, run it with structured inputs, and see the arrays, matrices
trees, lists, stacks, pointers, and return values move as the function executes.&lt;/p&gt;
&lt;p&gt;It is built for those moments when reading the code is not enough and you want
to &lt;em&gt;view&lt;/em&gt; why the answer changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-demo.gif" alt="DSA View View demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Try It?&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🧠 &lt;strong&gt;Step through real TypeScript&lt;/strong&gt;&lt;br&gt;
Paste or edit a function, validate it, then run the exact code in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🧩 &lt;strong&gt;Views that match the data&lt;/strong&gt;&lt;br&gt;
Arrays become bars, matrices become grids, trees become node graphs, linked lists become chains, and two-pointer area problems get their own visual view.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🌳 &lt;strong&gt;DSA-friendly inputs out of the box&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;TreeNode&lt;/code&gt;, &lt;code&gt;ListNode&lt;/code&gt;, &lt;code&gt;MinHeap&lt;/code&gt;, &lt;code&gt;MaxHeap&lt;/code&gt;, &lt;code&gt;PriorityQueue&lt;/code&gt;, nested arrays
matrices, strings, numbers, and class-style inputs are supported without
ceremony.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔎 &lt;strong&gt;39 built-in examples&lt;/strong&gt;&lt;br&gt;
Search by name, browse…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;All right, let's take a look together!&lt;/p&gt;




&lt;h2&gt;
  
  
  📝 Designing DSA View View
&lt;/h2&gt;

&lt;p&gt;DSA View View has four main responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Editor&lt;/li&gt;
&lt;li&gt;Compile&lt;/li&gt;
&lt;li&gt;Runtime&lt;/li&gt;
&lt;li&gt;Visualize&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also a Verification step in the UI, where the user provides input values before the code is executed.&lt;/p&gt;

&lt;p&gt;The overall flow looks like 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwpqg19os1rtxlfqkidks.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwpqg19os1rtxlfqkidks.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each part is already a little complicated on its own, and they interact with one another quite deeply.&lt;/p&gt;

&lt;p&gt;I could see during the design phase that a flat project structure would eventually leave future-me wandering around the repository like a lost hiker. 🌲&lt;/p&gt;

&lt;p&gt;So I decided to use &lt;strong&gt;FSD (Feature-Sliced Design)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I previously wrote about how I learned FSD here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/nyaomaru/lets-learn-feature-sliced-design-fsd-15bb"&gt;https://dev.to/nyaomaru/lets-learn-feature-sliced-design-fsd-15bb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A simplified version of the project structure looks 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;src/
├── app/                # App startup and global styles
├── pages/
│   └── main/           # Main page that composes the features
├── widgets/
│   ├── editor-panel/   # UI around the editor
│   ├── control-panel/  # Compile / Verification / Runtime controls
│   └── header/
├── features/
│   ├── code-editing/   # Monaco Editor, formatting, and parsing
│   ├── compilation/    # Compile behavior
│   ├── code-execution/ # AST transforms, execution, step recording, input forms
│   ├── visualization/  # Visualization detection and views
│   └── shareable-url/
├── entities/
│   ├── code/           # Code, types, and compile results
│   ├── execution/      # ExecutionState and ExecutionStep
│   ├── data-structure/ # TreeNode, ListNode, and friends
│   └── algorithm-example/
└── shared/
    ├── ui/             # Generic components such as Button, Card, and Dialog
    └── lib/            # Guards, cloning, serializers, and other utilities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, &lt;code&gt;features/code-execution&lt;/code&gt; owns the behavior of executing code.&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;code&gt;ExecutionState&lt;/code&gt; and &lt;code&gt;ExecutionStep&lt;/code&gt; describe domain concepts, so they live in &lt;code&gt;entities/execution&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then &lt;code&gt;pages/main&lt;/code&gt; combines the individual features and coordinates the overall flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After Compile succeeds, extract the signature and move to Verification&lt;/li&gt;
&lt;li&gt;After receiving the inputs, start the Runtime&lt;/li&gt;
&lt;li&gt;When the Runtime step changes, highlight the corresponding line in the Editor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each slice is consumed through a public API such as &lt;code&gt;index.ts&lt;/code&gt;, and dependencies are allowed to flow only from higher layers to lower layers.&lt;/p&gt;

&lt;p&gt;I also verify those dependency directions and public API boundaries with architecture tests.&lt;/p&gt;

&lt;p&gt;Drawing those boundaries helps prevent the classic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I changed the Runtime. Why is the Editor broken now?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A mystery nobody ordered.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛡️ &lt;code&gt;is-kit&lt;/code&gt;: Protecting the App from &lt;code&gt;unknown&lt;/code&gt; Hell
&lt;/h2&gt;

&lt;p&gt;FSD can organize dependency directions, but it cannot automatically make values entering the application safe.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;DSA View View&lt;/strong&gt;, mysterious &lt;code&gt;unknown&lt;/code&gt; values come flying in from many directions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AST nodes returned by &lt;code&gt;Babel Parser&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Messages sent between &lt;code&gt;Web Worker&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;JSON restored from a shareable URL&lt;/li&gt;
&lt;li&gt;Runtime snapshots recorded from user code&lt;/li&gt;
&lt;li&gt;Arrays, trees, graphs, and heaps being inspected as visualization candidates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;TypeScript&lt;/code&gt; is wonderfully reliable at compile time.&lt;/p&gt;

&lt;p&gt;But at runtime, it does not interrogate a value and ask.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Are you &lt;em&gt;really&lt;/em&gt; an &lt;code&gt;ExecutionState&lt;/code&gt;, or are you just wearing its name tag?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is where my type guard library, &lt;a href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;&lt;code&gt;is-kit&lt;/code&gt;&lt;/a&gt;, comes in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;&lt;code&gt;is-kit&lt;/code&gt;&lt;/a&gt; is a small, zero-dependency library for building and composing reusable &lt;code&gt;TypeScript&lt;/code&gt; type guards.&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;and&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;arrayOf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;hasKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;oneOfValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;or&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;predicateToRefine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Guard&lt;/span&gt;&lt;span class="p"&gt;,&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="s2"&gt;is-kit&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;isNumericString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;predicateToRefine&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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;value&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;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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;isNonArrayObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isArray&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;isNumericValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isNumericString&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;isNumericArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;arrayOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isNumericValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Small guards can be combined like LEGO bricks to create more complicated runtime checks.&lt;/p&gt;

&lt;p&gt;For example, the code that finds class methods in an AST defines a guard.&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;isMethodNodeType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;oneOfValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ClassMethod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MethodDefinition&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;hasType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hasKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&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;isMethodLikeNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MethodLikeNode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;isObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MethodLikeNode&lt;/span&gt;&lt;span class="o"&gt;&amp;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;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;hasType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;isMethodNodeType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&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;After a value passes this guard, it is narrowed from a plain &lt;code&gt;unknown&lt;/code&gt; to &lt;code&gt;MethodLikeNode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The guard can then be passed directly to &lt;code&gt;filter&lt;/code&gt;.&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;members&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;classNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;isMethodLikeNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is extremely convenient.&lt;/p&gt;

&lt;p&gt;Without &lt;a href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;&lt;code&gt;is-kit&lt;/code&gt;&lt;/a&gt;, checks like this would have multiplied across the repository:&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;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="nx"&gt;value&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;amp;&amp;amp;&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually, slightly different versions of the same guard would appear everywhere.&lt;/p&gt;

&lt;p&gt;Six months later, I would be asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What is the difference between this &lt;code&gt;isObject&lt;/code&gt; and that &lt;code&gt;isObject&lt;/code&gt;?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And congratulations—we would have built a second maze inside the first maze.&lt;/p&gt;

&lt;p&gt;At the time of writing, shared guards are used from around &lt;strong&gt;69 files&lt;/strong&gt; under &lt;code&gt;src&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;Monaco&lt;/code&gt; and &lt;code&gt;Babel&lt;/code&gt; are the stars on stage, &lt;code&gt;is-kit&lt;/code&gt; is the very serious bouncer standing at every entrance to the AST, Worker, share URL, Runtime, and Visualization layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mr. Unknown&lt;/strong&gt; is not getting in.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ynmx4d0fqp4mpny8zga.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ynmx4d0fqp4mpny8zga.png" alt="Mr. Unknown insect damage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also use &lt;code&gt;Zod&lt;/code&gt; in the Verification forms, but the responsibilities are different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;is-kit&lt;/code&gt;: Internal narrowing, filtering, and reusable runtime guards&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Zod&lt;/code&gt;: Input form schemas, validation messages, and user-facing errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of making one library solve every problem, &lt;code&gt;is-kit&lt;/code&gt; handles internal runtime safety while &lt;code&gt;Zod&lt;/code&gt; handles user input validation.&lt;/p&gt;

&lt;p&gt;I am very glad I built &lt;code&gt;is-kit&lt;/code&gt; before building this application. Fighting all those &lt;code&gt;unknown&lt;/code&gt; values with my bare hands would have made &lt;em&gt;me&lt;/em&gt; the first thing that needed visualizing.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✏️ Editor
&lt;/h2&gt;

&lt;p&gt;The Editor uses &lt;a href="https://microsoft.github.io/monaco-editor/" rel="noopener noreferrer"&gt;Monaco Editor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Monaco is the browser-focused editor component also used by &lt;code&gt;VS Code&lt;/code&gt;, giving the application syntax highlighting, completion, and &lt;code&gt;TypeScript&lt;/code&gt; diagnostics.&lt;/p&gt;

&lt;p&gt;The downside is that Monaco is not exactly tiny.&lt;/p&gt;

&lt;p&gt;Loading everything immediately made the initial display heavier, so DSA View View first renders a lightweight &lt;code&gt;textarea&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The same &lt;code&gt;textarea&lt;/code&gt; is also used as the &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; fallback, preventing the editor area from becoming empty while Monaco is loading.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt;
  &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Code Editor"&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onFocus&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onActivate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes, DSA View View waits briefly and prepares Monaco with &lt;code&gt;requestIdleCallback&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the browser does not support &lt;code&gt;requestIdleCallback&lt;/code&gt;, loading starts normally. If the user focuses the &lt;code&gt;textarea&lt;/code&gt; before that, Monaco preparation begins immediately.&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;CodeEditor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;prepareCodeEditorModule&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kr"&gt;module&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="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CodeEditor&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;Once loading finishes, the lightweight editor is replaced by Monaco while preserving the same source code.&lt;/p&gt;

&lt;p&gt;It looks like an editor, but secretly it is still a &lt;code&gt;textarea&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A tiny editor body-double strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static &lt;code&gt;TypeScript&lt;/code&gt; Analysis
&lt;/h3&gt;

&lt;p&gt;Static analysis uses the &lt;code&gt;TypeScript Worker&lt;/code&gt; included with Monaco.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TypeScript Language Service&lt;/code&gt; runs in a separate Worker from the editor itself and returns type and syntax problems as markers.&lt;/p&gt;

&lt;p&gt;Those markers are converted into the application's &lt;code&gt;CompilationError&lt;/code&gt; model and used to control the Compile button and display errors.&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;type&lt;/span&gt; &lt;span class="nx"&gt;CompilationError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;message&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="nl"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;warning&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;The Compile button is disabled only when an &lt;code&gt;error&lt;/code&gt; exists. Warnings alone do not prevent compilation.&lt;/p&gt;

&lt;p&gt;One important detail is that &lt;strong&gt;&lt;code&gt;Babel&lt;/code&gt; does not perform &lt;code&gt;TypeScript&lt;/code&gt; type checking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The responsibilities are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monaco's &lt;code&gt;TypeScript&lt;/code&gt; Worker: Diagnose types and syntax&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Babel&lt;/code&gt;: Transform &lt;code&gt;TypeScript&lt;/code&gt; syntax into &lt;code&gt;JavaScript&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keeping that distinction clear saved me from blaming Babel for crimes it did not commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Registering DSA Classes in the Editor
&lt;/h3&gt;

&lt;p&gt;Many &lt;code&gt;LeetCode&lt;/code&gt; problems provide classes such as &lt;code&gt;TreeNode&lt;/code&gt; and &lt;code&gt;ListNode&lt;/code&gt; automatically.&lt;/p&gt;

&lt;p&gt;DSA View View also provides common classes so users do not have to declare them every time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TreeNode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ListNode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GraphNode&lt;/code&gt; / &lt;code&gt;_Node&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TrieNode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PriorityQueue&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MinHeap&lt;/code&gt; / &lt;code&gt;MaxHeap&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Deque&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UnionFind&lt;/code&gt; / &lt;code&gt;DSU&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Counter&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Monaco provides a mechanism called &lt;code&gt;setExtraLibs&lt;/code&gt;, which lets the application add these type definitions to the Editor:&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;monaco&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typescript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typescriptDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setExtraLibs&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ts:algorithm-visualizer-prepared-classes.ts&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;However, &lt;code&gt;setExtraLibs&lt;/code&gt; only supports type analysis inside the Editor. It does not magically create those classes at Runtime.&lt;/p&gt;

&lt;p&gt;So the Compile and Runtime pipelines also prepend the same class definitions to the user's code as a prelude.&lt;/p&gt;

&lt;p&gt;If the user declares a &lt;code&gt;class&lt;/code&gt;, &lt;code&gt;interface&lt;/code&gt;, or &lt;code&gt;type&lt;/code&gt; with the same name, DSA View View skips injecting the prepared definition.&lt;/p&gt;

&lt;p&gt;Imagine carefully writing your own &lt;code&gt;ListNode&lt;/code&gt;, only for another &lt;code&gt;ListNode&lt;/code&gt; to emerge from behind it.&lt;/p&gt;

&lt;p&gt;That is not type safety. That is a summer horror movie.&lt;/p&gt;

&lt;h3&gt;
  
  
  Formatting
&lt;/h3&gt;

&lt;p&gt;Formatting uses &lt;code&gt;Prettier&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Prettier core, &lt;code&gt;TypeScript&lt;/code&gt; plugin, and &lt;code&gt;Estree&lt;/code&gt; plugin are dynamically imported only when needed and registered as Monaco's &lt;code&gt;Document Formatting Provider&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Users can therefore format their code with &lt;code&gt;Command/Ctrl + S&lt;/code&gt; or &lt;code&gt;Shift + Alt + F&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  📌 From the Compile Button to Verification
&lt;/h2&gt;

&lt;p&gt;So far, I have described "Compile" as if it were one large operation.&lt;/p&gt;

&lt;p&gt;Internally, however, the FSD slice &lt;code&gt;features/compilation&lt;/code&gt; does not own the whole flow.&lt;/p&gt;

&lt;p&gt;When the user presses the Compile button, &lt;code&gt;pages/main&lt;/code&gt; coordinates these operations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;features/compilation&lt;/code&gt; checks whether the &lt;code&gt;TypeScript&lt;/code&gt; can be transformed into &lt;code&gt;JavaScript&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The parser in &lt;code&gt;features/code-editing&lt;/code&gt; extracts the function or class signature&lt;/li&gt;
&lt;li&gt;If everything succeeds, the UI moves to Verification&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;features/code-execution&lt;/code&gt; displays an input form matching that signature&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To the user, this feels like one continuous Compile step.&lt;/p&gt;

&lt;p&gt;Inside the application, each responsibility remains separate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transforming &lt;code&gt;TypeScript&lt;/code&gt; with Babel
&lt;/h3&gt;

&lt;p&gt;The application uses Babel to transform &lt;code&gt;TypeScript&lt;/code&gt;.&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;prepared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepareTypeScriptCodeWithClasses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prepared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;typescript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;input.ts&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;DSA View View runs entirely in the browser, so it is not invoking &lt;code&gt;tsc&lt;/code&gt; on a &lt;code&gt;Node.js&lt;/code&gt; server.&lt;/p&gt;

&lt;p&gt;Instead, it uses &lt;code&gt;@babel/standalone&lt;/code&gt; to transform &lt;code&gt;TypeScript&lt;/code&gt; syntax into &lt;code&gt;JavaScript&lt;/code&gt; in the browser.&lt;/p&gt;

&lt;p&gt;Before transformation, the application prepends any prepared classes that the user has not declared themselves.&lt;/p&gt;

&lt;p&gt;If the source contains imports for those prepared classes, they are removed because the browser execution environment cannot resolve those modules.&lt;/p&gt;

&lt;p&gt;Again, an important reminder:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Babel's &lt;code&gt;TypeScript&lt;/code&gt; preset primarily removes type information. It does not type-check the program.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Monaco handles type errors. Babel checks whether the syntax can be transformed.&lt;/p&gt;

&lt;p&gt;The generated &lt;code&gt;JavaScript&lt;/code&gt; from this stage is also not executed directly on the main thread.&lt;/p&gt;

&lt;p&gt;For the Runtime, the original source is instrumented separately and then executed inside a &lt;code&gt;Web Worker&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is the fun part—and the topic of the next article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extracting Function Signatures from the AST
&lt;/h3&gt;

&lt;p&gt;After Compile succeeds, DSA View View needs to build an input form.&lt;/p&gt;

&lt;p&gt;Suppose the user writes this 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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;trap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&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 source code is parsed into an AST with &lt;code&gt;Babel Parser&lt;/code&gt;, and DSA View View extracts information 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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;trap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;parameters&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="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="s2"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number-array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;optional&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="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;returnType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&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;The parser supports more than ordinary function declarations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function declarations&lt;/li&gt;
&lt;li&gt;Arrow functions assigned to variables&lt;/li&gt;
&lt;li&gt;Function expressions assigned to variables&lt;/li&gt;
&lt;li&gt;LeetCode-style factory functions that return another function&lt;/li&gt;
&lt;li&gt;Class declarations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a class, the parser extracts the constructor and callable methods. &lt;code&gt;private&lt;/code&gt; methods are currently excluded.&lt;/p&gt;

&lt;p&gt;For class-design problems such as &lt;code&gt;LRUCache&lt;/code&gt; and &lt;code&gt;MedianFinder&lt;/code&gt;, it extracts the class name, constructor, method names, and arguments.&lt;/p&gt;

&lt;p&gt;When the source contains multiple helper classes, DSA View View avoids prioritizing prepared classes as solution candidates and compares the number of callable methods to select the likely design class.&lt;/p&gt;

&lt;p&gt;This selection is heuristic, so it cannot perfectly identify every possible class structure yet.&lt;/p&gt;

&lt;p&gt;There are always more creative ways to write JavaScript than I expect. JavaScript considers this a feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating the Verification Form
&lt;/h3&gt;

&lt;p&gt;For ordinary functions, the input form is built from the extracted signature using &lt;code&gt;React Hook Form&lt;/code&gt; and &lt;code&gt;Zod&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Supported input types include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;number&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;number[]&lt;/code&gt; / &lt;code&gt;string[]&lt;/code&gt; / &lt;code&gt;boolean[]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;number[][]&lt;/code&gt; / &lt;code&gt;string[][]&lt;/code&gt; / &lt;code&gt;boolean[][]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TreeNode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ListNode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GraphNode&lt;/code&gt; / &lt;code&gt;_Node&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The input UI and validation behavior change depending on the type.&lt;/p&gt;

&lt;p&gt;For example, a &lt;code&gt;number[]&lt;/code&gt; accepts both:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1, 2, 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both formats are converted into a real array that can be passed to the Runtime.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;TreeNode&lt;/code&gt;, the application constructs a tree from a level-order array.&lt;/p&gt;

&lt;p&gt;When a problem has multiple &lt;code&gt;TreeNode&lt;/code&gt; parameters, users can also select a specific node from the first root.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;ListNode&lt;/code&gt;, users can build a linked list from an array or node-based input and specify the cycle position.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;GraphNode&lt;/code&gt;, a cyclic graph structure is constructed from a &lt;code&gt;LeetCode&lt;/code&gt;-style adjacency list.&lt;/p&gt;

&lt;p&gt;Class-design problems use a different UI.&lt;/p&gt;

&lt;p&gt;Instead of the normal parameter form powered by &lt;code&gt;React Hook Form&lt;/code&gt; and &lt;code&gt;Zod&lt;/code&gt;, DSA View View displays the same &lt;code&gt;Operations&lt;/code&gt; and &lt;code&gt;Arguments&lt;/code&gt; JSON format used by &lt;code&gt;LeetCode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;MedianFinder&lt;/code&gt; uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Operations: ["MedianFinder", "addNum", "addNum", "findMedian"]
Arguments:  [[], [1], [2], []]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This form validates class-design-specific requirements, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The number of operations matches the number of argument lists&lt;/li&gt;
&lt;li&gt;The first operation matches the class name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the Compile button starts a chain of separate responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Babel verifies that transformation is possible&lt;/li&gt;
&lt;li&gt;AST analysis extracts the signature&lt;/li&gt;
&lt;li&gt;The Verification layer generates the appropriate input form&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pages/main&lt;/code&gt; connects the entire flow from the Editor to Verification&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Summary
&lt;/h2&gt;

&lt;p&gt;In this article, we followed the path from writing &lt;code&gt;TypeScript&lt;/code&gt; in DSA View View to generating the inputs needed for execution.&lt;/p&gt;

&lt;p&gt;The broad flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Render a lightweight &lt;code&gt;textarea&lt;/code&gt; first&lt;/li&gt;
&lt;li&gt;Prepare Monaco Editor in the background&lt;/li&gt;
&lt;li&gt;Diagnose types and syntax with the &lt;code&gt;TypeScript&lt;/code&gt; Worker&lt;/li&gt;
&lt;li&gt;Use Babel to check whether the &lt;code&gt;TypeScript&lt;/code&gt; can be transformed into &lt;code&gt;JavaScript&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Extract the function or class signature from the AST&lt;/li&gt;
&lt;li&gt;Generate a Verification form based on the detected types&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The important design decision was not forcing the Editor, diagnostics, syntax transformation, and input UI into one giant operation.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;&lt;code&gt;is-kit&lt;/code&gt;&lt;/a&gt; safely narrows &lt;code&gt;unknown&lt;/code&gt; values from the AST, Workers, JSON, and runtime snapshots&lt;/li&gt;
&lt;li&gt;Monaco's &lt;code&gt;TypeScript&lt;/code&gt; Worker diagnoses types and syntax&lt;/li&gt;
&lt;li&gt;Babel transforms &lt;code&gt;TypeScript&lt;/code&gt; syntax into &lt;code&gt;JavaScript&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AST analysis extracts the signature needed by the Verification UI&lt;/li&gt;
&lt;li&gt;The Verification form validates inputs and converts them into Runtime values&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pages/main&lt;/code&gt; connects the separate steps and advances the UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keeping those responsibilities separate made the flow much easier to understand and extend.&lt;/p&gt;

&lt;p&gt;In the next article, we will finally enter the heart of DSA View View: the Runtime.&lt;/p&gt;

&lt;p&gt;That is where &lt;strong&gt;Mr. View&lt;/strong&gt; stops politely waiting beside the Editor and starts watching every move your variables make. 👀&lt;/p&gt;

&lt;p&gt;There are still unsupported patterns and types, so Issues and PRs are always welcome!&lt;/p&gt;

&lt;p&gt;And if you enjoy the project, I would be very happy if you left a GitHub ⭐!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;https://github.com/nyaomaru/dsa-view-view&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Built a Tool to Visualize DSA. Let’s Learn Together! (DSA View View 👀👀)</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 15 Jul 2026 12:04:25 +0000</pubDate>
      <link>https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo</link>
      <guid>https://dev.to/nyaomaru/i-built-a-tool-to-visualize-dsa-lets-learn-together-dsa-view-view--djo</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I’m &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer currently fighting the intense European heatwave by building DIY window screens here in the Netherlands. 🛠️&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/data-science-collective/should-you-still-learn-to-code-in-2026-034685e17707" rel="noopener noreferrer"&gt;https://medium.com/data-science-collective/should-you-still-learn-to-code-in-2026-034685e17707&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As this article also discusses, I believe that &lt;strong&gt;improving our fundamental engineering skills is still essential in the age of AI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine that AI makes an F1 car fully autonomous. 🏎️&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Would you let someone without even a driver’s license enter a race as its driver?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or imagine that AI completely automates maintenance during pit stops. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Would you put someone who knows absolutely nothing about cars, their parts, or their internal structure in charge of that AI?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI is certainly reducing the amount of code we need to write by hand. Typing quickly and memorizing every small piece of syntax or every method are becoming less important.&lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;can we confidently release a product without understanding its fundamental concepts or implementation?&lt;/strong&gt; If something goes wrong in production, can we take responsibility and fix it?&lt;/p&gt;

&lt;p&gt;My answer was &lt;strong&gt;no&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Building things faster is obviously a good thing. But if we build without understanding, we may simply produce fragile software with no long-term sustainability at a faster rate.&lt;/p&gt;

&lt;p&gt;The real value comes from building meaningful things quickly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Then, how can we develop the fundamental skills we still need in the AI era?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I believe one useful approach is learning &lt;strong&gt;DSA: Data Structures and Algorithms&lt;/strong&gt;. So I decided to start learning DSA again.&lt;/p&gt;

&lt;p&gt;However, while solving problems on &lt;code&gt;LeetCode&lt;/code&gt;, I repeatedly ran into the same problem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to visualize the data flow and understand what is happening, but I still can’t clearly see it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I used the skills I have developed through frontend engineering and built a tool that visualizes the execution flow of DSA implementations! 🚀&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;
        dsa-view-view
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DSA View View allows you to understand DSA to see the data flow. 👀👀 Of course, it's free.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nyaomaru/dsa-view-view/./public/readme-view-view.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Freadme-view-view.png" alt="DSA View View" width="100%"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DSA View View&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;DSA View View turns TypeScript algorithm functions into step-by-step visual
stories. 👀👀&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-tv.gif" alt="DSA View View TV"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Write code, run it with structured inputs, and see the arrays, matrices
trees, lists, stacks, pointers, and return values move as the function executes.&lt;/p&gt;
&lt;p&gt;It is built for those moments when reading the code is not enough and you want
to &lt;em&gt;view&lt;/em&gt; why the answer changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-demo.gif" alt="DSA View View demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Try It?&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🧠 &lt;strong&gt;Step through real TypeScript&lt;/strong&gt;&lt;br&gt;
Paste or edit a function, validate it, then run the exact code in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🧩 &lt;strong&gt;Views that match the data&lt;/strong&gt;&lt;br&gt;
Arrays become bars, matrices become grids, trees become node graphs, linked lists become chains, and two-pointer area problems get their own visual view.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🌳 &lt;strong&gt;DSA-friendly inputs out of the box&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;TreeNode&lt;/code&gt;, &lt;code&gt;ListNode&lt;/code&gt;, nested arrays, matrices, strings, numbers, and class
style inputs are supported without ceremony.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔎 &lt;strong&gt;39 built-in examples&lt;/strong&gt;&lt;br&gt;
Search by name, browse by category, and jump into…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flt3slpuvq0bt9yzzjtkm.gif" alt="DSA View View demo" width="600" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I’ll explain how &lt;strong&gt;DSA View View&lt;/strong&gt; works and how we can use it to study DSA.&lt;/p&gt;

&lt;p&gt;Let’s take a look together!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;&lt;br&gt;
I may sound confident so far, but I’m definitely not a DSA expert. I’m still learning, just like many of you.&lt;/p&gt;

&lt;p&gt;In fact, I built this tool precisely because I was struggling. When I realized that I couldn’t immediately solve Binary Search, I started to panic a little. 😸&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🖥️ What Is DSA View View?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DSA View View&lt;/strong&gt; is a tool that executes functions and classes written in &lt;code&gt;TypeScript&lt;/code&gt; and lets you inspect how variables and return values change on each line through a runtime timeline.&lt;/p&gt;

&lt;p&gt;The easiest way to understand is to try it yourself!&lt;/p&gt;

&lt;p&gt;Open the tool and click the &lt;strong&gt;Run Demo&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frdur3bu1s24luupivhly.png" alt="Run Demo Button" width="798" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll quickly see how the workflow works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write your implementation&lt;/li&gt;
&lt;li&gt;Compile it&lt;/li&gt;
&lt;li&gt;Enter the input values&lt;/li&gt;
&lt;li&gt;Run it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s really it.&lt;/p&gt;

&lt;p&gt;Although I created it primarily for DSA problems, you can also use it to inspect and test smaller &lt;code&gt;TypeScript&lt;/code&gt; implementations.&lt;/p&gt;

&lt;p&gt;And, of course, it’s completely free!&lt;/p&gt;




&lt;h2&gt;
  
  
  🤔 What Can It Do?
&lt;/h2&gt;

&lt;p&gt;With DSA View View, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write DSA implementations in &lt;code&gt;TypeScript&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Test implementations with different input values&lt;/li&gt;
&lt;li&gt;Move forward and backward through runtime steps&lt;/li&gt;
&lt;li&gt;Visualize supported data structures and algorithms&lt;/li&gt;
&lt;li&gt;Review LeetCode solutions and confirm your understanding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also use it as a lightweight environment for executing functions or formatting code blocks for technical articles such as Dev.to 😸&lt;/p&gt;

&lt;p&gt;Feel free to experiment with it and find your own use cases!&lt;/p&gt;




&lt;h2&gt;
  
  
  🧑‍🏫 How to Use It
&lt;/h2&gt;

&lt;p&gt;The main workflow consists of three modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Editor&lt;/li&gt;
&lt;li&gt;Verification&lt;/li&gt;
&lt;li&gt;Runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at each one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Editor
&lt;/h2&gt;

&lt;p&gt;First, write your implementation!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg96n2pdp7atrfm0i9y9k.png" alt=" " width="799" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Editor is designed to feel similar to a basic IDE.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TypeScript&lt;/code&gt; diagnostics are available by default, so the editor can detect some errors while you write.&lt;/p&gt;

&lt;p&gt;You can also press &lt;code&gt;Cmd/Ctrl + S&lt;/code&gt; to format your code with Prettier, so feel free to write first and clean it up afterward.&lt;/p&gt;

&lt;p&gt;Common classes used in DSA problems, such as &lt;code&gt;TreeNode&lt;/code&gt; and &lt;code&gt;ListNode&lt;/code&gt;, are already available.&lt;/p&gt;

&lt;p&gt;You don’t need to declare or import them every time.&lt;/p&gt;

&lt;p&gt;You can also define your own classes or replace the provided definitions when necessary.&lt;/p&gt;

&lt;p&gt;Once your implementation is ready, click &lt;strong&gt;Compile Code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If compilation fails, the tool displays the relevant location and error message so that you can fix it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fss7ylft3mi1q5ur2sw1z.png" alt=" " width="800" height="752"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also an &lt;strong&gt;Example&lt;/strong&gt; menu containing several common implementations.&lt;/p&gt;

&lt;p&gt;For example, if you want to quickly inspect a Heap Sort implementation and see how it behaves, you can load the example instead of writing everything manually.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;

&lt;p&gt;In Verification mode, you define the input values that should be passed to your function or class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhz024r1f92790yj7bkrf.png" alt=" " width="800" height="751"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter a test value for each argument.&lt;/p&gt;

&lt;p&gt;For arrays, both of the following formats are supported:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1, 2, 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once your input values are ready, click &lt;strong&gt;Run&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Runtime
&lt;/h2&gt;

&lt;p&gt;Finally, let’s inspect the runtime!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7bziyhlkont1v3m2odh7.png" alt=" " width="800" height="755"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you click &lt;strong&gt;Run&lt;/strong&gt; in Verification mode, your implementation is executed.&lt;/p&gt;

&lt;p&gt;Runtime mode then lets you play through the execution steps or move backward and forward manually.&lt;/p&gt;

&lt;p&gt;When the tool recognizes supported logic, &lt;strong&gt;an additional visualization is displayed in a modal&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not every possible implementation is supported yet, of course. If something you need is missing, I would be happy to receive an issue or pull request!&lt;/p&gt;

&lt;p&gt;You can move backward and forward through the executed lines to inspect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which line is currently running&lt;/li&gt;
&lt;li&gt;How variables change&lt;/li&gt;
&lt;li&gt;Where values are returned&lt;/li&gt;
&lt;li&gt;How the execution reaches its final result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can return to the beginning, jump directly to the end, or move through the timeline one step at a time.&lt;/p&gt;

&lt;p&gt;The main execution process runs entirely in the browser.&lt;/p&gt;


&lt;h2&gt;
  
  
  Share 🐈
&lt;/h2&gt;

&lt;p&gt;DSA View View also includes a sharing feature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvzdkh18relxhb1sfir94.png" alt="DSA View View Share button" width="800" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can create a URL that preserves your implementation and share it with someone else.&lt;/p&gt;

&lt;p&gt;Use the &lt;strong&gt;Share&lt;/strong&gt; button at the top of the page to post it on social media or copy the link directly.&lt;/p&gt;

&lt;p&gt;Share your implementations, compare different solutions, and let’s learn together!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The shared URL contains your implementation. Do not paste private, confidential, or proprietary code into the tool before sharing it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  What Is That Thing in the Top-Right Corner? 👀👀
&lt;/h2&gt;

&lt;p&gt;Meet Mr. View.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4k6eygcli1kzrkr62qn7.gif" alt=" " width="510" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mr. View watches over your implementation.&lt;/p&gt;

&lt;p&gt;Nothing more.&lt;/p&gt;

&lt;p&gt;Nothing less.&lt;/p&gt;

&lt;p&gt;He is simply there to support you.&lt;/p&gt;

&lt;p&gt;When you need to concentrate, press the TV button to hide him. Press it again to bring him back.&lt;/p&gt;

&lt;p&gt;However, if Mr. View is enough to distract you, you may not be ready for an attack from ten simultaneous Slack notifications. 😸&lt;/p&gt;


&lt;h2&gt;
  
  
  ✏️ How Should We Study DSA?
&lt;/h2&gt;

&lt;p&gt;Now you know how to use DSA View View.&lt;/p&gt;

&lt;p&gt;The next question is probably&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which problems should I solve?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;LeetCode is an obvious place to start, and the study plan from Tech Interview Handbook also provides a useful collection of practice problems. 👇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.techinterviewhandbook.org/coding-interview-study-plan/" rel="noopener noreferrer"&gt;https://www.techinterviewhandbook.org/coding-interview-study-plan/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try solving these problems with &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;DSA View View&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once your implementation works, use the runtime timeline to inspect the data flow and understand exactly how the algorithm reaches its answer.&lt;/p&gt;

&lt;p&gt;You can also use tools such as ChatGPT, Codex, Claude, Claude Code, Gemini, and Grok to explore your solution further.&lt;/p&gt;

&lt;p&gt;Don’t limit yourself to asking&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this implementation correct?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Try asking questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What would happen if I rewrote this DFS solution using BFS?&lt;/li&gt;
&lt;li&gt;Could Dynamic Programming solve this problem?&lt;/li&gt;
&lt;li&gt;Are there any other reasonable approaches?&lt;/li&gt;
&lt;li&gt;What are the time and space complexities?&lt;/li&gt;
&lt;li&gt;Why is this approach better than the alternatives?&lt;/li&gt;
&lt;li&gt;Under which conditions would another approach be better?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI becomes much more useful for learning when it helps us compare and understand different approaches instead of only generating a final answer. 👍&lt;/p&gt;
&lt;h3&gt;
  
  
  Why TypeScript Instead of Python? 🐍
&lt;/h3&gt;

&lt;p&gt;The simple answer is that &lt;code&gt;TypeScript&lt;/code&gt; is my favorite language.&lt;/p&gt;

&lt;p&gt;I mainly work as a frontend engineer, so &lt;code&gt;TypeScript&lt;/code&gt; is also the language in which I feel most comfortable experimenting and learning.&lt;/p&gt;

&lt;p&gt;However, I designed the tool so that additional languages could be supported in the future.&lt;/p&gt;

&lt;p&gt;If there is enough demand for another language, please leave a comment or open an issue!&lt;/p&gt;


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

&lt;p&gt;AI is helping us write code faster and faster.&lt;/p&gt;

&lt;p&gt;However, understanding what happens inside an implementation remains an important engineering skill.&lt;/p&gt;

&lt;p&gt;In fact, I believe that this ability may become even more valuable as AI-generated code becomes increasingly common.&lt;/p&gt;

&lt;p&gt;I built DSA View View because I wanted a tool that could help me strengthen those fundamental skills from the ground up.&lt;/p&gt;

&lt;p&gt;To be honest, I still have a lot to learn about DSA.&lt;/p&gt;

&lt;p&gt;That is exactly why I hope we can learn together.&lt;/p&gt;

&lt;p&gt;Please leave a comment or open an issue if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want support for a particular problem or data structure&lt;/li&gt;
&lt;li&gt;You have an idea for a new visualization&lt;/li&gt;
&lt;li&gt;You find a bug&lt;/li&gt;
&lt;li&gt;You want support for another programming language&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s train our DSA muscles together! 💪😸&lt;/p&gt;

&lt;p&gt;If you like it, please give a star ⭐&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;
        dsa-view-view
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DSA View View allows you to understand DSA to see the data flow. 👀👀 Of course, it's free.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nyaomaru/dsa-view-view/./public/readme-view-view.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Freadme-view-view.png" alt="DSA View View" width="100%"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DSA View View&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;DSA View View turns TypeScript algorithm functions into step-by-step visual
stories. 👀👀&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-tv.gif" alt="DSA View View TV"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Write code, run it with structured inputs, and see the arrays, matrices
trees, lists, stacks, pointers, and return values move as the function executes.&lt;/p&gt;
&lt;p&gt;It is built for those moments when reading the code is not enough and you want
to &lt;em&gt;view&lt;/em&gt; why the answer changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dsa-view-view.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fdsa-view-view%2FHEAD%2F.%2Fpublic%2Fdemo%2Fdsa-view-view-demo.gif" alt="DSA View View demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Try It?&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🧠 &lt;strong&gt;Step through real TypeScript&lt;/strong&gt;&lt;br&gt;
Paste or edit a function, validate it, then run the exact code in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🧩 &lt;strong&gt;Views that match the data&lt;/strong&gt;&lt;br&gt;
Arrays become bars, matrices become grids, trees become node graphs, linked lists become chains, and two-pointer area problems get their own visual view.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🌳 &lt;strong&gt;DSA-friendly inputs out of the box&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;TreeNode&lt;/code&gt;, &lt;code&gt;ListNode&lt;/code&gt;, nested arrays, matrices, strings, numbers, and class
style inputs are supported without ceremony.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔎 &lt;strong&gt;39 built-in examples&lt;/strong&gt;&lt;br&gt;
Search by name, browse by category, and jump into…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/dsa-view-view" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;And I also launched on ProductHunt! Come say hello and let me know what you think 😸 👇&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://www.producthunt.com/products/dsa-view-view" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;producthunt.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>showdev</category>
      <category>typescript</category>
      <category>dsa</category>
      <category>react</category>
    </item>
    <item>
      <title>Trying Declarative Partial Updates: A Future API for Replacing HTML Later</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 01 Jul 2026 12:42:05 +0000</pubDate>
      <link>https://dev.to/nyaomaru/trying-declarative-partial-updates-a-future-api-for-replacing-html-later-2g43</link>
      <guid>https://dev.to/nyaomaru/trying-declarative-partial-updates-a-future-api-for-replacing-html-later-2g43</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I'm &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who was cheering for the World Cup during tropical nights in the Netherlands while nearly melting from heat exhaustion. 🫠⚽ (But yesterday was comfortable 😺)&lt;/p&gt;

&lt;p&gt;How do you usually build frontend applications?&lt;/p&gt;

&lt;p&gt;Do you build SPAs with &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; / &lt;code&gt;Svelte&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Do you use SSR / SSG / ISR frameworks like &lt;code&gt;Next&lt;/code&gt; / &lt;code&gt;Remix&lt;/code&gt; / &lt;code&gt;Nuxt&lt;/code&gt; / &lt;code&gt;Astro&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;There are many ways to build frontend applications, but today it is very common to update the DOM on the client side using JavaScript.&lt;/p&gt;

&lt;p&gt;Even when using UI libraries and frameworks like &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; / &lt;code&gt;Svelte&lt;/code&gt;, or SSR frameworks like &lt;code&gt;Next&lt;/code&gt; / &lt;code&gt;Remix&lt;/code&gt; / &lt;code&gt;Nuxt&lt;/code&gt; / &lt;code&gt;Astro&lt;/code&gt;, there are still many cases where part of the screen is eventually updated by client-side JavaScript.&lt;/p&gt;

&lt;p&gt;But is that really always the best answer?&lt;/p&gt;

&lt;p&gt;Are there cases where we are forcing JavaScript on the client to handle work that could naturally be handled on the server?&lt;/p&gt;

&lt;p&gt;In response to that kind of question, the Chrome team introduced an experimental API called DPU, or Declarative Partial Updates. 🚀&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://developer.chrome.com/blog/declarative-partial-updates?hl=en" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.chrome.com%2Fstatic%2Fblog%2Fdeclarative-partial-updates%2Fimage%2Fthumbnail.png" height="450" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://developer.chrome.com/blog/declarative-partial-updates?hl=en" rel="noopener noreferrer" class="c-link"&gt;
            Declarative partial updates &amp;nbsp;|&amp;nbsp; Blog &amp;nbsp;|&amp;nbsp; Chrome for Developers
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn about new out-of-order streaming capabilities and the renewed HTML insertion and streaming methods available for testing from Chrome 148
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.gstatic.com%2Fdevrel-devsite%2Fprod%2Fv11431966d26d9f049ef61662c2b798f1cdee8af320f1ba0f77a43eee64301d60%2Fchrome%2Fimages%2Ffavicon.png" width="32" height="32"&gt;
          developer.chrome.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In this article, I want to explore what Declarative Partial Updates are, what problems they try to solve, and why they might matter.&lt;/p&gt;

&lt;p&gt;I will focus especially on the out-of-order streaming mechanism that can replace parts of HTML later without writing client-side JavaScript for the replacement itself.&lt;/p&gt;

&lt;p&gt;Let's dive in!&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqjkwpwvwoitaac69eml0.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqjkwpwvwoitaac69eml0.png" alt="nyaomaru soccer" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 What are Declarative Partial Updates?
&lt;/h2&gt;

&lt;p&gt;Declarative Partial Updates are, roughly speaking&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A mechanism where you declare part of your HTML as “this area will be replaced later”, and then update only that part with HTML that arrives later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, imagine you want to return the overall page HTML immediately, but some data is slower to fetch.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The header is instant&lt;/li&gt;
&lt;li&gt;The layout is fast&lt;/li&gt;
&lt;li&gt;The user profile is also pretty fast&lt;/li&gt;
&lt;li&gt;But only the recommendations API is slow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In that case, we often show a loading state on the client, fetch data, and update the DOM with JavaScript. In &lt;code&gt;React&lt;/code&gt;, you might reach for something like &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With DPU, the server can first return HTML like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Recommendations&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"recommendations"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Loading recommendations...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The area surrounded by &lt;code&gt;&amp;lt;?start name="recommendations"&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt; is a &lt;strong&gt;region that can be replaced later&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then, when the recommendations HTML is ready on the server, it can stream HTML like this later.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"recommendations"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Advanced CSS Layouts&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Modern HTML APIs&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Web Performance Basics&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At that point, the browser finds the region named &lt;code&gt;recommendations&lt;/code&gt; and replaces the loading UI with the contents of this &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Wait, does that feel a bit weird?&lt;/p&gt;

&lt;p&gt;Exactly. The wild part is that &lt;strong&gt;up to this point, we did not write any JavaScript for the replacement, and no framework is involved&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In other words, you no longer need to write client-side JavaScript like this just to replace that area:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#recommendations&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You stream HTML, and the browser understands where that HTML should go.&lt;/p&gt;

&lt;p&gt;That is the interesting part of Declarative Partial Updates.&lt;/p&gt;

&lt;p&gt;DPU also has &lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt;, not only &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt; is basically a marker that says, “insert later HTML here.”&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;marker&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"placeholder"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"placeholder"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Here is streamed content!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In this case, the browser finds the marker named &lt;code&gt;placeholder&lt;/code&gt; and inserts the contents of the later &lt;code&gt;&amp;lt;template for="placeholder"&amp;gt;&lt;/code&gt; at that position.&lt;/p&gt;

&lt;p&gt;On the other hand, the &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt; pair used mainly in this article is for showing placeholder content, such as a loading UI, and replacing that entire range later.&lt;/p&gt;

&lt;p&gt;So, roughly&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt; means “insert here”&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt; means “replace this range”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That mental model should be enough to start.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt; can also be used by leaving the same marker inside streamed content, which lets you append list items one by one. That is pretty interesting too.&lt;/p&gt;

&lt;p&gt;In the first half of this article, I focus mainly on replacing loading UI, so I mostly use &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the later sample, I also try an example that uses &lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt; to append asset links sequentially.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  🤔 Why do we need Declarative Partial Updates?
&lt;/h2&gt;

&lt;p&gt;At this point, you might think&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Wait, frameworks like React or Astro can already do this, right?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes. They can.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; / &lt;code&gt;Svelte&lt;/code&gt; / &lt;code&gt;Next&lt;/code&gt; / &lt;code&gt;Remix&lt;/code&gt; / &lt;code&gt;Nuxt&lt;/code&gt; / &lt;code&gt;Astro&lt;/code&gt;, you can show loading states, receive API results, and update parts of the screen. Many of us do this every day.&lt;/p&gt;

&lt;p&gt;But wait a second. A lot of that is implemented by &lt;strong&gt;client-side JavaScript updating the DOM&lt;/strong&gt;, right?&lt;/p&gt;

&lt;p&gt;A common flow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The server returns HTML&lt;/li&gt;
&lt;li&gt;The browser displays the HTML&lt;/li&gt;
&lt;li&gt;Client-side JavaScript is loaded&lt;/li&gt;
&lt;li&gt;JavaScript calls an API&lt;/li&gt;
&lt;li&gt;The API result is put into state&lt;/li&gt;
&lt;li&gt;The framework updates the DOM&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, this is an extremely common frontend architecture today.&lt;/p&gt;

&lt;p&gt;But if part of the screen is “something the server can already produce as HTML”, do we really need to make client-side JavaScript do that work every time?&lt;/p&gt;

&lt;p&gt;For example, the recommendations HTML can be generated on the server like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Advanced CSS Layouts&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Modern HTML APIs&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Web Performance Basics&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If all we want to do is send that to the browser, it can feel a bit indirect to do this.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/recommendations&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="nf"&gt;then&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="o"&gt;=&amp;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;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;items&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="nf"&gt;setRecommendations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&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 fetch JSON, convert it to HTML on the client, update state, and then update the DOM.&lt;/p&gt;

&lt;p&gt;That is convenient, but it is also a bit roundabout. &lt;/p&gt;

&lt;p&gt;What makes DPU interesting is that it points in another direction&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the server can produce HTML, why not stream that HTML directly and let the browser insert it into the right place?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So DPU is &lt;strong&gt;not a replacement for &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; / &lt;code&gt;Svelte&lt;/code&gt;&lt;/strong&gt;. It is more like a lower-level browser primitive.&lt;/p&gt;

&lt;p&gt;It may allow the browser to understand, as part of HTML itself, some of the partial update work that frameworks currently handle.&lt;/p&gt;

&lt;p&gt;If that happens, the boundary between client-side responsibility and server-side responsibility becomes even more important.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What can be done with HTML?&lt;/li&gt;
&lt;li&gt;What should be done with JavaScript?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By redesigning these boundaries and declaring things in a way that fits the browser, we may be able to unlock browser capabilities that we are not fully using yet.&lt;/p&gt;

&lt;p&gt;But we should not misunderstand &lt;strong&gt;the client still has responsibilities&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This discussion is not about replacing state management, and interactive features still need JavaScript.&lt;/p&gt;

&lt;p&gt;For example, forms, modals, charts, and similar UI should still be managed on the client side, while static text or server-generated HTML based on slower API responses may be a better fit for HTML streaming.&lt;/p&gt;

&lt;p&gt;The responsibility split becomes more complex, but the UX may improve a lot. This is definitely something worth watching.&lt;/p&gt;


&lt;h2&gt;
  
  
  🏠 This may expand what SPAs can do
&lt;/h2&gt;

&lt;p&gt;DPU is &lt;strong&gt;not about rejecting SPAs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Personally, I see it as something that may expand the possibilities of SPAs.&lt;/p&gt;

&lt;p&gt;Until now, SPAs have often followed this mental model.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fetch data as JSON
    ↓
Put it into client-side state
    ↓
Re-render components
    ↓
Update the DOM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But if DPU and the new HTML insertion / streaming APIs become available, another option appears.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The server returns HTML
    ↓
HTML is streamed
    ↓
The browser inserts it into the existing DOM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That means an SPA could potentially choose different update strategies for different parts of the UI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch JSON and render on the client&lt;/li&gt;
&lt;li&gt;Generate HTML on the server and insert it directly&lt;/li&gt;
&lt;li&gt;Return only the shell initially, then stream slower parts later&lt;/li&gt;
&lt;li&gt;Perform page-transition-like updates with HTML partials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is really interesting.&lt;/p&gt;

&lt;p&gt;SPAs often carry the image of “doing everything with client-side JavaScript”, but they may become more hybrid in the future. The meaning of the word SPA itself may change.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State that belongs on the client stays on the client&lt;/li&gt;
&lt;li&gt;HTML that can be produced on the server is produced on the server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the browser does not merely display that HTML. It also understands &lt;strong&gt;where and how to insert it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If this direction continues, frontend architecture may become even more flexible and deeper than it is today.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧪 APIs for streaming HTML from JavaScript are also coming
&lt;/h2&gt;

&lt;p&gt;The interesting part of DPU is not only out-of-order streaming with &lt;code&gt;&amp;lt;template for="..."&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Chrome team is also proposing a new set of APIs for inserting and streaming HTML from JavaScript.&lt;/p&gt;

&lt;p&gt;Even today, there are several ways to dynamically insert HTML.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertAdjacentHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;beforeend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But they all have slightly different behavior.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does it overwrite existing content?&lt;/li&gt;
&lt;li&gt;Does it append after the existing content?&lt;/li&gt;
&lt;li&gt;Are &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags executed?&lt;/li&gt;
&lt;li&gt;What happens with sanitization?&lt;/li&gt;
&lt;li&gt;How does it interact with Trusted Types?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a lot of subtle differences.&lt;/p&gt;

&lt;p&gt;Honestly, I do not think many developers can confidently explain all of those differences from memory. I definitely cannot.&lt;/p&gt;

&lt;p&gt;The new APIs try to make HTML insertion easier to understand with more consistent names.&lt;/p&gt;

&lt;p&gt;For example, static HTML insertion looks like this.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;p&amp;gt;This is a new paragraph&amp;lt;/p&amp;gt;&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;contentElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#content-to-update&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;contentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newHTML&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is not an API that appends to the end, like &lt;code&gt;insertAdjacentHTML("beforeend", html)&lt;/code&gt;. It replaces the existing contents of &lt;code&gt;contentElement&lt;/code&gt; with &lt;code&gt;newHTML&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A useful way to understand the difference is&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;setHTML()&lt;/code&gt; is the safer API that runs through a sanitizer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setHTMLUnsafe()&lt;/code&gt; disables the sanitizer by default and lets you handle HTML more directly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then comes the really interesting part of streaming versions.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contentElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#content-to-update&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/content.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeThrough&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;TextDecoderStream&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;streamHTMLUnsafe&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is pretty wild.&lt;/p&gt;

&lt;p&gt;It means we may be able to take HTML returned by &lt;code&gt;fetch()&lt;/code&gt; and stream it directly into an element &lt;strong&gt;without waiting for the entire response to finish downloading&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;SPAs have not benefited much from HTML streaming after the initial document load.&lt;/p&gt;

&lt;p&gt;The initial document can be streamed from the server, but later screen updates often become JSON fetch + client render.&lt;/p&gt;

&lt;p&gt;With APIs like this, SPA updates may also be able to benefit from HTML streaming.&lt;/p&gt;

&lt;p&gt;That is why I think this may expand the possibilities of SPAs.&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚠️ “unsafe” does not mean “never use it”
&lt;/h2&gt;

&lt;p&gt;When you see a name like &lt;code&gt;streamHTMLUnsafe()&lt;/code&gt;, you might think&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unsafe!? That sounds terrifying.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I thought that too at first.&lt;/p&gt;

&lt;p&gt;But this &lt;code&gt;unsafe&lt;/code&gt; does not mean “you must never use it.” It is closer to a warning that &lt;strong&gt;the sanitizer is disabled by default, so you need to think carefully about whether the input is trusted&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, it would be dangerous to stream user-generated HTML directly into the DOM.&lt;/p&gt;

&lt;p&gt;But if the HTML is generated by your own trusted server, there may be valid use cases.&lt;/p&gt;

&lt;p&gt;Of course, before using this in production, you need to think carefully about sanitizers, Trusted Types, script execution, browser support, and other security concerns.&lt;/p&gt;


&lt;h2&gt;
  
  
  ➕ What happens when DPU and the streaming APIs are combined?
&lt;/h2&gt;

&lt;p&gt;This is the most interesting part.&lt;/p&gt;

&lt;p&gt;DPU’s &lt;code&gt;&amp;lt;template for="..."&amp;gt;&lt;/code&gt; and the new HTML streaming APIs are &lt;strong&gt;separate APIs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But combining them makes the story even deeper.&lt;/p&gt;

&lt;p&gt;For example, imagine placing placeholders in an SPA screen.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"page-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Loading...&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"page-content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Loading content...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, during a page update, the server streams HTML.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"page-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Dashboard&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"page-content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This is the dashboard content.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Instead of manually targeting the DOM with JavaScript.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#page-title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;titleHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#page-content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contentHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;the browser may be able to understand where &lt;code&gt;page-title&lt;/code&gt; and &lt;code&gt;page-content&lt;/code&gt; should be applied.&lt;/p&gt;

&lt;p&gt;In other words, even in SPA-style page transitions, something like this may become possible.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fetch a new page's HTML partial
    ↓
Stream the HTML
    ↓
Update only the necessary places via template for
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Part of the work that frameworks currently handle with Virtual DOM, compilers, or fine-grained reactivity may be shifted to browser-native HTML streaming / partial updates.&lt;/p&gt;

&lt;p&gt;That makes DPU feel like more than just a small HTML API. It feels like something that could expand the design space of frontend architecture.&lt;/p&gt;

&lt;p&gt;Of course, this is still experimental. This is not a “let's all use this in production right now” kind of API.&lt;/p&gt;

&lt;p&gt;But the old assumption&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An SPA fetches JSON and renders on the client&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;may start to change.&lt;/p&gt;

&lt;p&gt;HTML may evolve from “a static document loaded once at the beginning” into “a UI unit that can be streamed, replaced, and updated.”&lt;/p&gt;

&lt;p&gt;That is pretty exciting, right?&lt;/p&gt;


&lt;h2&gt;
  
  
  🚀 Trying it with Node.js DPU samples
&lt;/h2&gt;

&lt;p&gt;So far, we have talked about the concept. I also built a small Node.js sample app to try this out.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/declarative-partial-updates-sample" rel="noopener noreferrer"&gt;
        declarative-partial-updates-sample
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Sample repository for DPU (Declarative Partial Updates)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Declarative Partial Updates sample&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;A small Node.js sample app for trying Chrome's experimental Declarative Partial
Updates (DPU) feature.&lt;/p&gt;
&lt;p&gt;Images under &lt;code&gt;public/&lt;/code&gt; are served through the Node.js stream handler at &lt;code&gt;/public/...&lt;/code&gt;
then inserted from later DPU or HTML streaming chunks.&lt;/p&gt;
&lt;p&gt;Styles live in &lt;code&gt;public/styles.css&lt;/code&gt;. Shared timing and image constants live in
&lt;code&gt;features/shared.mjs&lt;/code&gt;, while public asset metadata and GitHub links live in
&lt;code&gt;features/public-assets.mjs&lt;/code&gt; so the sample behavior is easier to inspect and
adjust.&lt;/p&gt;
&lt;p&gt;The server is split by feature:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;features/home/&lt;/code&gt;: DPU document streaming sample HTML and stream chunks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;features/hybrid-shell/&lt;/code&gt;: hybrid shell HTML and route partial HTML&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;features/set-apis/&lt;/code&gt;: static and streaming HTML insertion sample HTML&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;features/public-assets.mjs&lt;/code&gt;: public asset metadata and stream handler&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;features/layout/&lt;/code&gt;: shared document layout HTML&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;features/layout.mjs&lt;/code&gt;: layout template renderer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;features/shared.mjs&lt;/code&gt;: common helpers and demo timing constants&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;public/html-stream.js&lt;/code&gt;: client-side static / streaming HTML insertion helper&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm start&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Open:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://localhost:3000/" rel="nofollow noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt;…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/declarative-partial-updates-sample" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;p&gt;This is an experimental feature, so you need Chrome Canary (Chrome v148 or later) or a Chrome build that includes this feature, with the experimental flag enabled.&lt;/p&gt;

&lt;p&gt;Open the following URL in Chrome’s address bar:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chrome://flags/#enable-experimental-web-platform-features&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Enable it, click “Relaunch”, and then run the sample. This article assumes a supported build with this flag enabled.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2r0obwjpvcguchppde0j.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2r0obwjpvcguchppde0j.png" alt=" " width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The demo app has roughly three pages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/              ... Document streaming
/hybrid-shell  ... Hybrid shell + streamed HTML route updates
/set-apis      ... Static / Streaming HTML APIs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first page, &lt;code&gt;/&lt;/code&gt;, demonstrates DPU out-of-order streaming.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiq3rgn0n0yb4sbyhlcgg.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiq3rgn0n0yb4sbyhlcgg.gif" alt=" " width="460" height="628"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The server first returns an HTML shell, and slower server-rendered fragments are streamed later as &lt;code&gt;&amp;lt;template for="..."&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, the initial HTML contains a placeholder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"panel"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Recommendations&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"recommendations"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Waiting for recommendations...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the browser shows the loading UI.&lt;/p&gt;

&lt;p&gt;Then, once the recommendations HTML is ready on the server, it streams a chunk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"recommendations"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Advanced CSS Layouts&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Modern HTML APIs&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Web Performance Basics&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser finds the DPU range named &lt;code&gt;recommendations&lt;/code&gt; and replaces the loading UI with the list.&lt;/p&gt;

&lt;p&gt;On this page, I stream multiple named regions at different timings, not only &lt;code&gt;recommendations&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hero image&lt;/li&gt;
&lt;li&gt;metric&lt;/li&gt;
&lt;li&gt;asset strip&lt;/li&gt;
&lt;li&gt;team activity&lt;/li&gt;
&lt;li&gt;streamed code block&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The asset strip also uses &lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt;. The initial HTML has a marker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"panel asset-panel"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Streamed public assets&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"asset-grid"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;marker&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"asset-list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the server streams chunks one by one whenever each asset link becomes ready.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"asset-list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- streamed asset link --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;marker&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"asset-list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By leaving the same marker again inside the streamed content, the next asset link can continue to be appended in the same place.&lt;/p&gt;

&lt;p&gt;So HTML does not have to wait until everything is complete from top to bottom. &lt;strong&gt;Fragments can be streamed in later as soon as they are ready.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the really interesting part of DPU.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; has several subtle rules, including constraints related to parent elements.&lt;/p&gt;

&lt;p&gt;This demo is a sample for exploring the direction of the API, but if you want to use it in production someday, you should carefully check the applicable range of &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt;, DOM movement during streaming, Trusted Types, sanitizers, and related details.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🌓 Trying a hybrid shell style architecture
&lt;/h2&gt;

&lt;p&gt;Next, &lt;code&gt;/hybrid-shell&lt;/code&gt; demonstrates streaming HTML route updates inside a hybrid shell style architecture.&lt;/p&gt;

&lt;p&gt;This is not a “pure SPA where everything is rendered on the client”. It is closer to an architecture where &lt;strong&gt;the whole document is not reloaded, the URL changes through the History API, and only the route content inside the shell is updated&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep client-side state alive, while replacing only the route content with server-generated HTML.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, this page has a counter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  Counter: &lt;span class="nt"&gt;&amp;lt;strong&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"counter"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"increment"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This counter is managed by client-side JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#increment&lt;/span&gt;&lt;span class="dl"&gt;"&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="s2"&gt;click&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;So this is clearly a client-side responsibility.&lt;/p&gt;

&lt;p&gt;On the other hand, route content is fetched from the server as HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loadRoute&lt;/span&gt; &lt;span class="o"&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;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;setActiveRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&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="nx"&gt;push&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;nextUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/hybrid-shell/dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/hybrid-shell/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;route&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pushState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nextUrl&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/partials/hybrid-shell/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;route&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="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceChildren&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;streamHTMLUnsafe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeThrough&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;TextDecoderStream&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;streamHTMLUnsafe&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;return&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;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;template&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceChildren&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneNode&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does is not “fetch JSON and render components on the client.” Instead, &lt;strong&gt;it streams HTML generated by the server directly into the view&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The counter state remains on the client.&lt;/p&gt;

&lt;p&gt;That means we can split responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interactive state such as the counter belongs to the client&lt;/li&gt;
&lt;li&gt;Server-generated route body can be streamed as HTML&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This feels close to the thinking behind island architecture in frameworks like &lt;code&gt;Astro&lt;/code&gt; / &lt;code&gt;Fresh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead of making the client do everything, we separate &lt;strong&gt;HTML that can be returned statically or from the server&lt;/strong&gt; from &lt;strong&gt;interactive client state&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Personally, I find this very interesting.&lt;/p&gt;

&lt;p&gt;At the very least, a shell with SPA-like navigation does not have to mean “everything is rendered by client-side JavaScript.” It may also expand into a hybrid shape that combines client state with streamed HTML.&lt;/p&gt;

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

&lt;p&gt;This &lt;code&gt;/hybrid-shell&lt;/code&gt; sample is &lt;strong&gt;not&lt;/strong&gt; a demo that replaces a range inside the shell using DPU’s &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Chrome team article also introduces the possibility of SPA-style page loads by combining &lt;code&gt;streamHTMLUnsafe()&lt;/code&gt; and &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, in my local tests, I could not confirm that streaming &lt;code&gt;&amp;lt;template for="..."&amp;gt;&lt;/code&gt; into &lt;code&gt;streamHTMLUnsafe()&lt;/code&gt; in this shell architecture updates an existing DPU range.&lt;/p&gt;

&lt;p&gt;The SPA-style page load described in the official article seems to point toward an outline page with processing instructions, where the new page’s &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; elements are streamed toward the end of the HTML and slotted into those instructions.&lt;/p&gt;

&lt;p&gt;So in this &lt;code&gt;/hybrid-shell&lt;/code&gt; sample, I do not handle DPU range replacement. Instead, I use the HTML streaming insertion API to stream server-generated route partials directly into &lt;code&gt;#hybrid-shell-view&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🎁 Trying Static / Streaming HTML APIs
&lt;/h2&gt;

&lt;p&gt;Finally, &lt;code&gt;/set-apis&lt;/code&gt; tries the new HTML insertion / streaming APIs separately from DPU’s out-of-order streaming.&lt;/p&gt;

&lt;p&gt;This page first checks whether the browser has the APIs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;support&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;ul class="list"&amp;gt;
    &amp;lt;li&amp;gt;setHTMLUnsafe: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;setHTMLUnsafe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;streamHTMLUnsafe: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;streamHTMLUnsafe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For static insertion, if &lt;code&gt;setHTMLUnsafe()&lt;/code&gt; is available, the demo uses it. Otherwise, it falls back to &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; and &lt;code&gt;replaceChildren()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;setHTMLUnsafe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;staticTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHTMLUnsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&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;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;template&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;markup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;staticTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceChildren&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneNode&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For streaming insertion, it pipes the fetched HTML response directly into &lt;code&gt;streamHTMLUnsafe()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/partials/set-apis/stream&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;streamTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceChildren&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;streamHTMLUnsafe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeThrough&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;TextDecoderStream&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;streamTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;streamHTMLUnsafe&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;return&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;If this works, we can stream chunks into an existing element as they arrive, &lt;strong&gt;instead of waiting until the entire HTML response has downloaded and inserting it all at once&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Traditionally, SPAs could benefit from HTML streaming for the initial document, but subsequent screen updates often became JSON fetch + client render.&lt;/p&gt;

&lt;p&gt;With APIs like this, SPAs may be able to benefit from HTML streaming even for later updates.&lt;/p&gt;

&lt;p&gt;That is the exciting part of DPU and the new HTML streaming APIs.&lt;/p&gt;

&lt;p&gt;The static insertion partial is returned from &lt;code&gt;/partials/set-apis/static&lt;/code&gt;, and the streaming insertion partial is returned from &lt;code&gt;/partials/set-apis/stream&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Summary
&lt;/h2&gt;

&lt;p&gt;In this article, I looked at Declarative Partial Updates introduced by the Chrome team.&lt;/p&gt;

&lt;p&gt;Declarative Partial Updates are, roughly&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A mechanism where you declare part of your HTML as “this area will be replaced later”, and then update only that part with HTML that arrives later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course, DPU does not replace &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; / &lt;code&gt;Svelte&lt;/code&gt; / &lt;code&gt;Next&lt;/code&gt; / &lt;code&gt;Remix&lt;/code&gt; / &lt;code&gt;Nuxt&lt;/code&gt; / &lt;code&gt;Astro&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Interactive UI, client-side state management, forms, modals, charts, drag and drop, and similar features still need JavaScript.&lt;/p&gt;

&lt;p&gt;But on the other hand, there may be more cases where we do not need to handle everything with client-side JavaScript.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML that can be generated on the server should be generated on the server&lt;/li&gt;
&lt;li&gt;State that should be managed on the client should be managed on the client&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the browser may come to understand &lt;strong&gt;not only how to display HTML, but also where streamed HTML should be inserted&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If this responsibility split progresses, frontend architecture may become more hybrid.&lt;/p&gt;

&lt;p&gt;Especially for SPAs, there may be another path beyond&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fetch JSON and render on the client&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, we may also be able to&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fetch / stream HTML partials and update via browser-native behavior&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I do not see this as the end of SPAs. I see it as something that may expand what SPAs can do.&lt;/p&gt;

&lt;p&gt;This is still experimental, so it is not an API to use in production right away.&lt;/p&gt;

&lt;p&gt;But the direction where HTML changes from “a document loaded once at the beginning” into “a UI unit that can be streamed, replaced, and updated” feels very important for the future of frontend development.&lt;/p&gt;

&lt;p&gt;DPU is definitely something to keep an eye on. 😺&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.chrome.com/blog/declarative-partial-updates?hl=en" rel="noopener noreferrer"&gt;https://developer.chrome.com/blog/declarative-partial-updates?hl=en&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/WICG/declarative-partial-updates" rel="noopener noreferrer"&gt;https://github.com/WICG/declarative-partial-updates&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/GoogleChromeLabs/template-for-polyfill" rel="noopener noreferrer"&gt;https://github.com/GoogleChromeLabs/template-for-polyfill&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/GoogleChromeLabs/html-setters-polyfill" rel="noopener noreferrer"&gt;https://github.com/GoogleChromeLabs/html-setters-polyfill&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/declarative-partial-updates-sample" rel="noopener noreferrer"&gt;https://github.com/nyaomaru/declarative-partial-updates-sample&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>html</category>
      <category>browser</category>
      <category>node</category>
    </item>
    <item>
      <title>The Difference Between satisfies, as, and Generics in TypeScript</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 17 Jun 2026 12:43:50 +0000</pubDate>
      <link>https://dev.to/nyaomaru/the-difference-between-satisfies-as-and-generics-in-typescript-5f9f</link>
      <guid>https://dev.to/nyaomaru/the-difference-between-satisfies-as-and-generics-in-typescript-5f9f</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I'm &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who recently obsessed with playing video game of "inscryption". 🃏&lt;/p&gt;

&lt;p&gt;In TypeScript, there are several syntaxes that look like they are "specifying a type."&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;as&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;satisfies&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;generics using &lt;code&gt;T extends xxx&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But these are not the same thing.&lt;/p&gt;

&lt;p&gt;Roughly speaking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;as&lt;/code&gt; asks TypeScript to &lt;strong&gt;trust you&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;satisfies&lt;/code&gt; asks TypeScript to &lt;strong&gt;check the value&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;generics let you &lt;strong&gt;encapsulate that check inside an API&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They all look type-related, but the responsibility lives in different places.&lt;/p&gt;

&lt;p&gt;You may see AI-generated code overusing &lt;code&gt;as&lt;/code&gt;, or codebases using &lt;code&gt;satisfies&lt;/code&gt; casually, or libraries using generics to enforce stricter APIs. These patterns appear quite often in real-world development.&lt;/p&gt;

&lt;p&gt;In this article, I want to explain the difference between &lt;code&gt;as&lt;/code&gt;, &lt;code&gt;satisfies&lt;/code&gt;, and generics not as "ways to specify a type," but as &lt;strong&gt;ways to decide where type responsibility should live&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's jump in.&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%2Fe3kkusmu97rasjez8s9s.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%2Fe3kkusmu97rasjez8s9s.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🙏 &lt;code&gt;as&lt;/code&gt; asks TypeScript to trust you
&lt;/h2&gt;

&lt;p&gt;In TypeScript, &lt;code&gt;as&lt;/code&gt; lets you tell the compiler:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please treat this value as this type, please 😭&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, the runtime value below is still a &lt;code&gt;string&lt;/code&gt;, but TypeScript treats it as a &lt;code&gt;number&lt;/code&gt;.&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;number&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "string"&lt;/span&gt;

&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// TypeScript thinks this is a number, so there is no compile-time error.&lt;/span&gt;
&lt;span class="c1"&gt;// But at runtime, this throws: "value.toFixed is not a function"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The important point is 👇&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;as&lt;/code&gt; does not transform the runtime value.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So using it for external data can be very dangerous.&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;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This does not check whether the parsed value is actually a &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It only tells TypeScript:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Trust me. This is a &lt;code&gt;User&lt;/code&gt;. Maybe.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, &lt;code&gt;as&lt;/code&gt; is for cases where &lt;strong&gt;a human knows something TypeScript cannot know&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is useful, but it does not guarantee anything by itself.&lt;/p&gt;

&lt;p&gt;If you write &lt;code&gt;as&lt;/code&gt;, &lt;strong&gt;the responsibility is on you.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🔍 &lt;code&gt;satisfies&lt;/code&gt; asks TypeScript to check the value
&lt;/h2&gt;

&lt;p&gt;Now let's look at &lt;code&gt;satisfies&lt;/code&gt;, which was introduced in TypeScript 4.9.&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;type&lt;/span&gt; &lt;span class="nx"&gt;RouteConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="na"&gt;path&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="nl"&gt;label&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="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;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Home&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;about&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;About&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="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;RouteConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With this, TypeScript checks whether the declared value matches the expected type structure.&lt;/p&gt;

&lt;p&gt;For example, if you add a property that does not exist on a route item, TypeScript reports an error.&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;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Home&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;about&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;About&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;nyaomaru&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Type error: nyaomaru does not exist on the route item type 😼&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;RouteConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The interesting part is 👇&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Even though &lt;code&gt;routes&lt;/code&gt; is checked against &lt;code&gt;RouteConfig&lt;/code&gt;, the type of &lt;code&gt;routes&lt;/code&gt; itself is not collapsed into &lt;code&gt;RouteConfig&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;routes&lt;/code&gt; is checked as &lt;code&gt;RouteConfig&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But the inferred type of &lt;code&gt;routes&lt;/code&gt; remains close to the actual object literal you wrote.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;keyof typeof routes&lt;/code&gt; becomes the union of the actual keys, not just &lt;code&gt;string&lt;/code&gt;.&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;type&lt;/span&gt; &lt;span class="nx"&gt;RouteName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// "home" | "about"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In other words, &lt;code&gt;satisfies&lt;/code&gt; checks that a value satisfies a given type while preserving the original inference as much as possible.&lt;/p&gt;

&lt;p&gt;Compare that with a regular type annotation.&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;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RouteConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Home&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;about&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;About&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RouteName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When you annotate &lt;code&gt;routes&lt;/code&gt; as &lt;code&gt;RouteConfig&lt;/code&gt;, TypeScript treats it as &lt;code&gt;RouteConfig&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;RouteConfig&lt;/code&gt; is a &lt;code&gt;Record&amp;lt;string, ...&amp;gt;&lt;/code&gt;, &lt;code&gt;RouteName&lt;/code&gt; becomes &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So when you want to validate a value against a type while keeping the concrete information from the actual value, &lt;code&gt;satisfies&lt;/code&gt; is often a better fit.&lt;/p&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;satisfies&lt;/code&gt; checks that a value matches a type without unnecessarily widening the value's inferred type.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🎁 Generics encapsulate the check inside an API
&lt;/h2&gt;

&lt;p&gt;At this point, you might think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Okay, then I should just use &lt;code&gt;satisfies&lt;/code&gt; everywhere. 😹&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And yes, sometimes that works well.&lt;/p&gt;

&lt;p&gt;But writing &lt;code&gt;satisfies&lt;/code&gt; every time can be annoying.&lt;br&gt;
And if someone forgets to write it, the intended check disappears.&lt;/p&gt;

&lt;p&gt;So what if we move that check into a function?&lt;/p&gt;

&lt;p&gt;That is where generics come in.&lt;/p&gt;

&lt;p&gt;As a quick recap, we could write 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;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Home&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="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;RouteConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But we can also wrap the pattern inside a function using generics.&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;function&lt;/span&gt; &lt;span class="nf"&gt;defineRoutes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;RouteConfig&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;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&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;routes&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;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineRoutes&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Home&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;Nice and clean.&lt;/p&gt;

&lt;p&gt;Now we get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validation that the value matches &lt;code&gt;RouteConfig&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;preservation of the concrete key &lt;code&gt;"home"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;no need for users to write &lt;code&gt;satisfies&lt;/code&gt; every time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But then this appears&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;RouteConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What is going on here???&lt;/p&gt;

&lt;p&gt;Let's break it down.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;T extends RouteConfig&lt;/code&gt; means: "&lt;code&gt;T&lt;/code&gt; must be assignable to &lt;code&gt;RouteConfig&lt;/code&gt;."&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;const T&lt;/code&gt; asks TypeScript to infer object literals and array literals as narrowly as possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here, &lt;code&gt;const&lt;/code&gt; is not the same as a &lt;code&gt;const&lt;/code&gt; variable declaration.&lt;/p&gt;

&lt;p&gt;It is not about whether a value can be reassigned.&lt;/p&gt;

&lt;p&gt;It is about making generic type parameter inference preserve literal information as much as possible.&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%2F8mu565dfikencnwt9ym9.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%2F8mu565dfikencnwt9ym9.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  📊 Comparing the three with config objects
&lt;/h2&gt;

&lt;p&gt;Here is the comparison so far.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Main responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;as Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Asks TypeScript to believe the value is that type&lt;/td&gt;
&lt;td&gt;The person writing the code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;satisfies Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Checks whether the value matches the type&lt;/td&gt;
&lt;td&gt;The value declaration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;T extends Type&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Constrains what an API can accept&lt;/td&gt;
&lt;td&gt;The API designer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So, in casual terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;as&lt;/code&gt; means: "Trust me. 🙏"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;satisfies&lt;/code&gt; means: "Please check if this is correct. 🔍"&lt;/li&gt;
&lt;li&gt;generics mean: "Only pass values that fit this API. 🎁"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So far, we have looked at config objects.&lt;/p&gt;

&lt;p&gt;But in real-world development, this difference becomes even more important when dealing with &lt;strong&gt;external data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;API responses, &lt;code&gt;localStorage&lt;/code&gt;, URL params, and form input cannot be protected by TypeScript types alone.&lt;/p&gt;

&lt;p&gt;For those values, we need runtime guards.&lt;/p&gt;

&lt;p&gt;And once we start writing runtime guards by hand, another problem appears 👇&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The existing TypeScript type and the handwritten schema can drift apart.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🤔 Thinking through &lt;code&gt;typedStruct&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This becomes easier to understand if we use a small validator API as an example.&lt;/p&gt;

&lt;p&gt;I'll use my type guard library, &lt;code&gt;is-kit&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;
        is-kit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Lightweight, zero-dependency toolkit for building `isFoo` style type guards in TypeScript. Runtime-safe 🛡️, composable 🧩, and ergonomic ✨. npm -&amp;gt; https://www.npmjs.com/package/is-kit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;is-kit&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/nyaomaru/is-kit/main/docs/public/iskit_image.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fis-kit%2Fmain%2Fdocs%2Fpublic%2Fiskit_image.png" width="600" alt="is-kit logo"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://www.npmjs.com/package/is-kit" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/cb829c46f855a6f184f255391ea5fe58bb6ed17112e34d4856acd61dc63179c2/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f69732d6b69742e737667" alt="npm version"&gt;
  &lt;/a&gt;
  &lt;a href="https://jsr.io/@nyaomaru/is-kit" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/b6648f6bf32eb9dff2136ce8538ccb4cc6af537c1127292b5fb0de416f7a69b4/68747470733a2f2f696d672e736869656c64732e696f2f6a73722f762f406e79616f6d6172752f69732d6b6974" alt="JSR"&gt;
  &lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/is-kit" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/9b30eeaac46ebced99b5e0dc290fd045bc34c738c66b5d95c4b6ee8fed358b34/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f64742f69732d6b69742e737667" alt="npm downloads"&gt;
  &lt;/a&gt;
  &lt;a href="https://github.com/nyaomaru/is-kit/blob/main/LICENSE" rel="noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/631cdf8c56ad84dd8657fe3371b93015b5474c517422f968ff4ec944bb28bf2f/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f6c2f69732d6b69742e7376673f73616e6974697a653d74727565" alt="License"&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; is a lightweight, zero-dependency toolkit for building reusable TypeScript &lt;strong&gt;type guards&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It helps you write small &lt;code&gt;isFoo&lt;/code&gt; functions, compose them into &lt;strong&gt;richer runtime checks&lt;/strong&gt;, and keep &lt;strong&gt;TypeScript narrowing&lt;/strong&gt; natural inside regular control flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime-safe&lt;/strong&gt; 🛡️, &lt;strong&gt;composable&lt;/strong&gt; 🧩, and &lt;strong&gt;ergonomic&lt;/strong&gt; ✨ without asking you to adopt a heavy schema workflow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build and reuse &lt;strong&gt;typed guards&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compose guards&lt;/strong&gt; with &lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, &lt;code&gt;not&lt;/code&gt;, &lt;code&gt;oneOf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate object&lt;/strong&gt; shapes and collections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parse or assert&lt;/strong&gt; &lt;code&gt;unknown&lt;/code&gt; values without a large schema framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://is-kit-docs.vercel.app/" rel="nofollow noopener noreferrer"&gt;📚 Documentation Site&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Best for &lt;strong&gt;app-internal narrowing, filtering, and reusable guards&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🤔 Why use &lt;code&gt;is-kit&lt;/code&gt;?&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Tired of rewriting the same &lt;code&gt;isFoo&lt;/code&gt; checks again and again?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; is a good fit when you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;write reusable &lt;code&gt;isX&lt;/code&gt;&lt;/strong&gt; functions instead of one-off inline checks&lt;/li&gt;
&lt;li&gt;keep runtime validation &lt;strong&gt;lightweight and dependency-free&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;narrow values directly&lt;/strong&gt; in &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and other TypeScript control flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;compose validation logic&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; is a lightweight library for building small type guards like &lt;code&gt;isString&lt;/code&gt; and &lt;code&gt;isNumber&lt;/code&gt;, then composing them with helpers like &lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, and &lt;code&gt;struct&lt;/code&gt;, while still allowing TypeScript narrowing to work naturally.&lt;/p&gt;

&lt;p&gt;Suppose an external API returns a &lt;code&gt;User&lt;/code&gt; 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;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With a normal &lt;code&gt;struct&lt;/code&gt;, we can create a guard for that object shape.&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;isUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;struct&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;isString&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="nx"&gt;isString&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;This is useful.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;struct&lt;/code&gt; can infer the return type from the schema, so &lt;code&gt;isUser&lt;/code&gt; can validate a value that looks like a &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But there is one problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is easy for the schema and the existing type to drift apart.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, suppose the &lt;code&gt;User&lt;/code&gt; type already exists, but we accidentally write the wrong key in the schema.&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;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&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;isUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;struct&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;isString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isString&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;This &lt;code&gt;struct&lt;/code&gt; call itself is valid.&lt;/p&gt;

&lt;p&gt;From the perspective of &lt;code&gt;struct&lt;/code&gt;, this is a perfectly valid schema for:&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;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="nl"&gt;displayName&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So &lt;code&gt;struct&lt;/code&gt; is useful for creating a type from a schema.&lt;/p&gt;

&lt;p&gt;But it does not synchronize that schema with an existing &lt;code&gt;User&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;A common dangerous workaround is to use &lt;code&gt;as&lt;/code&gt;.&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;isUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;struct&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;isString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isString&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="nx"&gt;Predicate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is extremely dangerous. ⚠️⚠️⚠️&lt;/p&gt;

&lt;p&gt;The schema says &lt;code&gt;displayName&lt;/code&gt;, but we are telling TypeScript&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Trust me. This is a guard for &lt;code&gt;User&lt;/code&gt;. Please 🙏&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That &lt;code&gt;as&lt;/code&gt; is not a check.&lt;/p&gt;

&lt;p&gt;It is just a self-declaration.&lt;/p&gt;

&lt;p&gt;Now, &lt;code&gt;satisfies&lt;/code&gt; can improve this.&lt;/p&gt;

&lt;p&gt;If the library exposes a schema shape type, we could write something like:&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;userSchema&lt;/span&gt; &lt;span class="o"&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;isString&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="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;TypedStructShape&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;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 TypeScript checks whether the schema corresponds to &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we write an unknown key or forget a required key, TypeScript can report an error.&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;userSchema&lt;/span&gt; &lt;span class="o"&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;isString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// name is missing, and displayName does not exist on User&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;TypedStructShape&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is better.&lt;/p&gt;

&lt;p&gt;But writing this every time is a bit annoying.&lt;/p&gt;

&lt;p&gt;Also, if the user forgets to write &lt;code&gt;satisfies TypedStructShape&amp;lt;User&amp;gt;&lt;/code&gt;, the schema and the type can drift apart again.&lt;/p&gt;

&lt;p&gt;So we can use generics to encapsulate this check inside the API.&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;isUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;typedStruct&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;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;isString&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="nx"&gt;isString&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;With this shape, users do not need to write &lt;code&gt;satisfies TypedStructShape&amp;lt;User&amp;gt;&lt;/code&gt; every time.&lt;/p&gt;

&lt;p&gt;Instead, the &lt;code&gt;typedStruct&amp;lt;User&amp;gt;()&lt;/code&gt; API itself checks 👇&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does this schema correspond to &lt;code&gt;User&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, using the framing from earlier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we are not using &lt;code&gt;as&lt;/code&gt; to ask TypeScript to trust us&lt;/li&gt;
&lt;li&gt;we are not asking users to write &lt;code&gt;satisfies&lt;/code&gt; every time&lt;/li&gt;
&lt;li&gt;we are using generics to encapsulate the check inside an API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the core idea.&lt;/p&gt;




&lt;p&gt;Let's look a little more concretely.&lt;/p&gt;

&lt;p&gt;The implementation idea for &lt;code&gt;typedStruct&lt;/code&gt; looks 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;type&lt;/span&gt; &lt;span class="nx"&gt;OptionalKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// WHY: Optional keys accept an empty object when picked in isolation.&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&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;extends&lt;/span&gt; &lt;span class="nb"&gt;Pick&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;K&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;K&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RequiredKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Exclude&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OptionalKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TypedStructShape&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;Extract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RequiredKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Predicate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&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="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;Extract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;OptionalKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;OptionalSchemaField&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
    &lt;span class="nx"&gt;Predicate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;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="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NoExtraKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;Exclude&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Shape&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;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TypedStructFields&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;TypedStructShape&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NoExtraKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TypedStructShape&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;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;function&lt;/span&gt; &lt;span class="nf"&gt;typedStruct&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;TypedStructShape&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TypedStructFields&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;S&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;options&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;exact&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Predicate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InferSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TypedStructFields&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// WHY: `typedStruct` keeps `struct` runtime behavior while using the target&lt;/span&gt;
    &lt;span class="c1"&gt;// type only to check that hand-written guard fields stay in sync.&lt;/span&gt;
    &lt;span class="nf"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&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;We can ignore the small details for now.&lt;/p&gt;

&lt;p&gt;The important part is 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="nx"&gt;typedStruct&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;First, &lt;code&gt;typedStruct&lt;/code&gt; receives the target type &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then this part:&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;TypedStructShape&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;means the actual schema &lt;code&gt;S&lt;/code&gt; passed by the user must correspond to &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But here is an important detail&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;S extends TypedStructShape&amp;lt;T&amp;gt;&lt;/code&gt; alone cannot completely prevent extra keys.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TypeScript uses structural typing.&lt;/p&gt;

&lt;p&gt;If a type has the required properties, it may still satisfy a constraint even if it also has additional properties.&lt;/p&gt;

&lt;p&gt;For example, if &lt;code&gt;User&lt;/code&gt; is &lt;code&gt;{ id: string; name: string }&lt;/code&gt;, then a schema like &lt;code&gt;{ id, name, displayName }&lt;/code&gt; has all required keys and one extra key.&lt;/p&gt;

&lt;p&gt;The constraint &lt;code&gt;S extends TypedStructShape&amp;lt;User&amp;gt;&lt;/code&gt; alone may still allow that.&lt;/p&gt;

&lt;p&gt;So we use &lt;code&gt;NoExtraKeys&lt;/code&gt; to make keys that do not exist in &lt;code&gt;TypedStructShape&amp;lt;T&amp;gt;&lt;/code&gt; become &lt;code&gt;never&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let's look at how &lt;code&gt;TypedStructShape&amp;lt;T&amp;gt;&lt;/code&gt; works.&lt;/p&gt;

&lt;p&gt;It separates required keys and optional keys from &lt;code&gt;T&lt;/code&gt;.&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;type&lt;/span&gt; &lt;span class="nx"&gt;OptionalKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&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;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&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;extends&lt;/span&gt; &lt;span class="nb"&gt;Pick&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;K&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;K&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RequiredKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Exclude&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OptionalKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;OptionalKeys&amp;lt;T&amp;gt;&lt;/code&gt; is used to pick optional properties like &lt;code&gt;name?: string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then &lt;code&gt;TypedStructShape&amp;lt;T&amp;gt;&lt;/code&gt; treats the keys differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;required keys become &lt;code&gt;Predicate&amp;lt;T[K]&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;optional keys become &lt;code&gt;OptionalSchemaField&amp;lt;Predicate&amp;lt;T[K]&amp;gt;&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means if a key is optional in the target type, the schema must also mark it as optional using something like &lt;code&gt;optionalKey(...)&lt;/code&gt;.&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;type&lt;/span&gt; &lt;span class="nx"&gt;TypedStructShape&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;Extract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RequiredKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Predicate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&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="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;Extract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;OptionalKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;OptionalSchemaField&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
    &lt;span class="nx"&gt;Predicate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here, &lt;code&gt;OptionalSchemaField&lt;/code&gt; is the internal type used to represent a schema field created by a helper like &lt;code&gt;optionalKey(...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, &lt;code&gt;TypedStructFields&amp;lt;T, S&amp;gt;&lt;/code&gt; prevents schema fields from having keys that do not exist in &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Roughly speaking, &lt;code&gt;NoExtraKeys&lt;/code&gt; takes keys that exist in &lt;code&gt;S&lt;/code&gt; but not in &lt;code&gt;Shape&lt;/code&gt;, and turns them into &lt;code&gt;never&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, if &lt;code&gt;User&lt;/code&gt; does not have &lt;code&gt;displayName&lt;/code&gt;, but the schema includes &lt;code&gt;displayName&lt;/code&gt;, that field becomes &lt;code&gt;never&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since a normal guard cannot be assigned to &lt;code&gt;never&lt;/code&gt;, TypeScript rejects the extra key.&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;type&lt;/span&gt; &lt;span class="nx"&gt;NoExtraKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;Exclude&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Shape&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;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TypedStructFields&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;TypedStructShape&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NoExtraKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TypedStructShape&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So &lt;code&gt;typedStruct&lt;/code&gt; is not just a helper that adds a type to &lt;code&gt;struct&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is an API for making an existing object type and a handwritten runtime guard harder to drift apart.&lt;/p&gt;

&lt;p&gt;One important point 👇&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;typedStruct&lt;/code&gt; does not automatically generate a runtime validator.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TypeScript types do not exist at runtime.&lt;/p&gt;

&lt;p&gt;Also, we cannot automatically generate &lt;code&gt;isString&lt;/code&gt; or &lt;code&gt;isNumber&lt;/code&gt; from the &lt;code&gt;User&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;So the guard itself still has to be written by hand.&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;isUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;typedStruct&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;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;isString&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="nx"&gt;isString&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;But the API can check whether the handwritten schema is still in sync with &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It's the tasty part of &lt;code&gt;typedStruct&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is especially useful when you already have API response types generated from something like OpenAPI.&lt;/p&gt;

&lt;p&gt;Here, imagine &lt;code&gt;ApiResponse&lt;/code&gt; is a generated response type.&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;type&lt;/span&gt; &lt;span class="nx"&gt;ArticleResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ApiResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/articles/{id}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get&lt;/span&gt;&lt;span class="dl"&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;isArticleResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;typedStruct&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ArticleResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;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;isNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;optionalKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isString&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;Here, &lt;code&gt;optionalKey(isString)&lt;/code&gt; means the object key itself may be missing.&lt;/p&gt;

&lt;p&gt;But if the key exists, the value must pass &lt;code&gt;isString&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So as a runtime check, this does not allow &lt;code&gt;{ summary: undefined }&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if &lt;code&gt;summary&lt;/code&gt; exists, it must be a &lt;code&gt;string&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;if &lt;code&gt;summary&lt;/code&gt; does not exist, that is OK&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a small but important distinction.&lt;/p&gt;

&lt;p&gt;The idea is not ❌&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The TypeScript property is optional, so I can omit the schema field.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, the idea is ✅&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The runtime guard should explicitly say that this key is optional.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That way, when the target type changes, the mismatch becomes easier to notice.&lt;/p&gt;

&lt;p&gt;Also, the compile-time key check in &lt;code&gt;typedStruct&lt;/code&gt; and the runtime check in &lt;code&gt;struct(..., { exact: true })&lt;/code&gt; are different things.&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;isUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;typedStruct&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isString&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="nx"&gt;isString&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="na"&gt;exact&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="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;NoExtraKeys&lt;/code&gt; is a compile-time check that prevents the schema author from writing extra keys in the schema.&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;code&gt;{ exact: true }&lt;/code&gt; is a runtime check that rejects actual runtime objects if they contain keys outside the schema.&lt;/p&gt;

&lt;p&gt;They may look similar, but they check different things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NoExtraKeys&lt;/code&gt; checks mistakes in the handwritten schema&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{ exact: true }&lt;/code&gt; checks extra keys in runtime data&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%2Fubximlmkrvqirlfv4owh.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%2Fubximlmkrvqirlfv4owh.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is exactly the theme of the article.&lt;/p&gt;

&lt;p&gt;Instead of silencing TypeScript with &lt;code&gt;as&lt;/code&gt;, we take a &lt;code&gt;satisfies&lt;/code&gt;-like check and encapsulate it inside an API with generics.&lt;/p&gt;

&lt;p&gt;One more important design point 👇&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The return type is not directly forced to &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, it is inferred from the actual &lt;code&gt;fields&lt;/code&gt; passed to the 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;Predicate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InferSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TypedStructFields&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So &lt;code&gt;T&lt;/code&gt; is used to check whether the schema is in sync with the existing type.&lt;/p&gt;

&lt;p&gt;But the actual guard type is inferred from the schema, just like &lt;code&gt;struct&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In other words, we are not doing 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="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Predicate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Instead, the existing type synchronization is handled by the generic constraint, while the actual guard type is derived from the schema.&lt;/p&gt;


&lt;h2&gt;
  
  
  🎯 Summary
&lt;/h2&gt;

&lt;p&gt;In this article, we looked at the difference between &lt;code&gt;as&lt;/code&gt;, &lt;code&gt;satisfies&lt;/code&gt;, and generics through the lens of &lt;strong&gt;where type responsibility lives&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Where the responsibility lives&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;as Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Asks TypeScript to trust you 🙏&lt;/td&gt;
&lt;td&gt;The person writing the code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;satisfies Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Checks whether a value matches a type 🔍&lt;/td&gt;
&lt;td&gt;The value declaration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;T extends Type&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Constrains what an API accepts 🎁&lt;/td&gt;
&lt;td&gt;The API designer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;as&lt;/code&gt; is not evil.&lt;/p&gt;

&lt;p&gt;Sometimes TypeScript cannot know something, and a human has to take responsibility for that missing information.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;as&lt;/code&gt; is not a check.&lt;/p&gt;

&lt;p&gt;When you use &lt;code&gt;as&lt;/code&gt; for external data or handwritten schemas, the code can look type-safe while skipping the actual validation.&lt;/p&gt;

&lt;p&gt;AI-generated code often papers over uncertainty with &lt;code&gt;as&lt;/code&gt;, so this is something worth watching for.&lt;/p&gt;

&lt;p&gt;When you really want to check whether a value has the right shape, first consider whether &lt;code&gt;satisfies&lt;/code&gt; can help.&lt;/p&gt;

&lt;p&gt;And when you find yourself repeating the same &lt;code&gt;satisfies&lt;/code&gt; pattern again and again, consider moving that constraint into an API with generics.&lt;/p&gt;

&lt;p&gt;Personally, I find this framing useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;as&lt;/code&gt; means: "Trust me."&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;satisfies&lt;/code&gt; means: "Please check if this is correct."&lt;/li&gt;
&lt;li&gt;generics mean: "Only pass values that fit this API."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;typedStruct&lt;/code&gt; in &lt;code&gt;is-kit&lt;/code&gt; is a good example of this difference.&lt;/p&gt;

&lt;p&gt;When you want to keep an existing object type and a runtime guard in sync, do not silence TypeScript with &lt;code&gt;as&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead, you can take a &lt;code&gt;satisfies&lt;/code&gt;-like check and encapsulate it inside an API using generics.&lt;/p&gt;

&lt;p&gt;This makes the safer way the natural way to use the API, and moves type responsibility closer to the API design.&lt;/p&gt;

&lt;p&gt;Happy TypeScript life. 🫰&lt;/p&gt;


&lt;h2&gt;
  
  
  Bonus
&lt;/h2&gt;

&lt;p&gt;The user-defined type guard library used in this article is &lt;code&gt;is-kit&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;
        is-kit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Lightweight, zero-dependency toolkit for building `isFoo` style type guards in TypeScript. Runtime-safe 🛡️, composable 🧩, and ergonomic ✨. npm -&amp;gt; https://www.npmjs.com/package/is-kit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;is-kit&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/nyaomaru/is-kit/main/docs/public/iskit_image.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fis-kit%2Fmain%2Fdocs%2Fpublic%2Fiskit_image.png" width="600" alt="is-kit logo"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://www.npmjs.com/package/is-kit" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/cb829c46f855a6f184f255391ea5fe58bb6ed17112e34d4856acd61dc63179c2/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f69732d6b69742e737667" alt="npm version"&gt;
  &lt;/a&gt;
  &lt;a href="https://jsr.io/@nyaomaru/is-kit" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/b6648f6bf32eb9dff2136ce8538ccb4cc6af537c1127292b5fb0de416f7a69b4/68747470733a2f2f696d672e736869656c64732e696f2f6a73722f762f406e79616f6d6172752f69732d6b6974" alt="JSR"&gt;
  &lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/is-kit" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/9b30eeaac46ebced99b5e0dc290fd045bc34c738c66b5d95c4b6ee8fed358b34/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f64742f69732d6b69742e737667" alt="npm downloads"&gt;
  &lt;/a&gt;
  &lt;a href="https://github.com/nyaomaru/is-kit/blob/main/LICENSE" rel="noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/631cdf8c56ad84dd8657fe3371b93015b5474c517422f968ff4ec944bb28bf2f/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f6c2f69732d6b69742e7376673f73616e6974697a653d74727565" alt="License"&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; is a lightweight, zero-dependency toolkit for building reusable TypeScript &lt;strong&gt;type guards&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It helps you write small &lt;code&gt;isFoo&lt;/code&gt; functions, compose them into &lt;strong&gt;richer runtime checks&lt;/strong&gt;, and keep &lt;strong&gt;TypeScript narrowing&lt;/strong&gt; natural inside regular control flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime-safe&lt;/strong&gt; 🛡️, &lt;strong&gt;composable&lt;/strong&gt; 🧩, and &lt;strong&gt;ergonomic&lt;/strong&gt; ✨ without asking you to adopt a heavy schema workflow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build and reuse &lt;strong&gt;typed guards&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compose guards&lt;/strong&gt; with &lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, &lt;code&gt;not&lt;/code&gt;, &lt;code&gt;oneOf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate object&lt;/strong&gt; shapes and collections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parse or assert&lt;/strong&gt; &lt;code&gt;unknown&lt;/code&gt; values without a large schema framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://is-kit-docs.vercel.app/" rel="nofollow noopener noreferrer"&gt;📚 Documentation Site&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Best for &lt;strong&gt;app-internal narrowing, filtering, and reusable guards&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🤔 Why use &lt;code&gt;is-kit&lt;/code&gt;?&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Tired of rewriting the same &lt;code&gt;isFoo&lt;/code&gt; checks again and again?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is-kit&lt;/code&gt; is a good fit when you want to:&lt;/p&gt;


&lt;ul&gt;

&lt;li&gt;

&lt;strong&gt;write reusable &lt;code&gt;isX&lt;/code&gt;&lt;/strong&gt; functions instead of one-off inline checks&lt;/li&gt;

&lt;li&gt;keep runtime validation &lt;strong&gt;lightweight and dependency-free&lt;/strong&gt;
&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;narrow values directly&lt;/strong&gt; in &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and other TypeScript control flow&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;compose validation logic&lt;/strong&gt;…&lt;/li&gt;

&lt;/ul&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/is-kit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;&lt;code&gt;typedStruct&lt;/code&gt; was added in v1.8, so please give it a try. 😻&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>programming</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>CHANGELOG.md is for Both Humans and AI Now, So Let’s Automate It</title>
      <dc:creator>nyaomaru</dc:creator>
      <pubDate>Wed, 03 Jun 2026 12:33:59 +0000</pubDate>
      <link>https://dev.to/nyaomaru/changelogmd-is-for-both-humans-and-ai-now-so-lets-automate-it-18dp</link>
      <guid>https://dev.to/nyaomaru/changelogmd-is-for-both-humans-and-ai-now-so-lets-automate-it-18dp</guid>
      <description>&lt;p&gt;Hoi hoi!&lt;/p&gt;

&lt;p&gt;I’m &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who recently discovered the deliciousness of a cheese whose name sounds a bit like Al Capone. 🧀&lt;/p&gt;

&lt;p&gt;Are you building personal projects?&lt;/p&gt;

&lt;p&gt;Or contributing to OSS?&lt;/p&gt;

&lt;p&gt;Or maybe you are busy playing &lt;strong&gt;Resident Evil 9 🧟 and CloverPit 🍀&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Whatever the case, I respect your admirable dedication as an engineer.&lt;/p&gt;

&lt;p&gt;Now, when managing OSS on GitHub, one file that becomes very important is &lt;code&gt;CHANGELOG.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Why is it important?&lt;/p&gt;

&lt;p&gt;For example, when a library I use gets updated, the first thing I usually check is &lt;code&gt;CHANGELOG.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Recently, I have been experimenting with an AI triage workflow. For Dependabot updates, I feed release notes and &lt;code&gt;CHANGELOG.md&lt;/code&gt; into AI, then ask Claude Code to evaluate the risk and help with triage.&lt;/p&gt;

&lt;p&gt;This has been very useful. I do not have to check everything manually, and that makes me happy 😺&lt;/p&gt;

&lt;p&gt;In other words, &lt;code&gt;CHANGELOG.md&lt;/code&gt; is becoming a document that is not only read by humans, but also read by AI as input for dependency update decisions.&lt;/p&gt;

&lt;p&gt;So, &lt;code&gt;CHANGELOG.md&lt;/code&gt; will continue to be very useful in the coming era.&lt;/p&gt;

&lt;p&gt;But surprisingly, many projects do not maintain it well.&lt;/p&gt;

&lt;p&gt;For example, even some very useful React development tools sometimes ship silent releases without any release notes at all.&lt;/p&gt;

&lt;p&gt;When that happens, users have to dig through commit history and figure out things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What new features were added?&lt;/li&gt;
&lt;li&gt;What changed?&lt;/li&gt;
&lt;li&gt;Is it safe to upgrade?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, busy engineers do not have time for that. I am not that busy, but if I had that time, I would rather play &lt;strong&gt;CloverPit 🍀&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, to protect my precious game time, I built an OSS tool that automatically generates &lt;code&gt;CHANGELOG.md&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/changelog-bot" rel="noopener noreferrer"&gt;
        changelog-bot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Automatic create changelog with AI. 🤖 It provides CLI and github actions. 🚀  https://www.npmjs.com/package/&lt;a class="mentioned-user" href="https://dev.to/nyaomaru"&gt;@nyaomaru&lt;/a&gt;/changelog-bot
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/nyaomaru/changelog-bot/main/public/ChangelogBot_logo02.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fchangelog-bot%2Fmain%2Fpublic%2FChangelogBot_logo02.png" alt="changelog-bot type logo" width="360"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;
    &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/nyaomaru/changelog-bot/main/public/ChangelogBot_image.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fchangelog-bot%2Fmain%2Fpublic%2FChangelogBot_image.png" width="600px" alt="changelog-bot logo"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Releases should feel exciting, not tedious.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@nyaomaru/changelog-bot&lt;/code&gt; 🤖 turns your Git history and release notes into a polished changelog entry (and optional PR) in a single run. Drop it into CI, run it locally, or hand it to your release captain—either way, you ship with a crisp changelog and zero copy-paste fatigue.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why changelog-bot?&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automated storytelling:&lt;/strong&gt; Combines commit history, PR titles, and release notes to produce human-ready changelog sections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM superpowers (optional):&lt;/strong&gt; Connect OpenAI or Anthropic for tone-aware summaries or skip API keys entirely and rely on a robust heuristic fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PR-ready output:&lt;/strong&gt; Can open a pull request with updated changelog, compare links, and release notes already wired up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe defaults:&lt;/strong&gt; Detects duplicate versions, keeps compare links current, and won’t fail a release if AI is down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI-native:&lt;/strong&gt; Works as a GitHub Action, reusable workflow, or plain CLI—no fragile scripting required.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-alert markdown-alert-important"&gt;
&lt;p class="markdown-alert-title"&gt;Important&lt;/p&gt;
&lt;p&gt;This project is currently in its early stages…&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/changelog-bot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;In this article, I will walk through the changes from v0.1 and what I am planning next.&lt;/p&gt;

&lt;p&gt;Let’s take a look!&lt;/p&gt;




&lt;h2&gt;
  
  
  🤖 What is changelog-bot?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/changelog-bot" rel="noopener noreferrer"&gt;&lt;code&gt;changelog-bot&lt;/code&gt;&lt;/a&gt; is a CLI and GitHub Action that automatically creates a Pull Request to update &lt;code&gt;CHANGELOG.md&lt;/code&gt; based on Git history, Pull Requests, and GitHub Release Notes.&lt;/p&gt;

&lt;p&gt;What it does is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collect commits and PRs from the previous release to the current release&lt;/li&gt;
&lt;li&gt;Categorize changes into sections such as &lt;code&gt;Added&lt;/code&gt;, &lt;code&gt;Changed&lt;/code&gt;, &lt;code&gt;Fixed&lt;/code&gt;, &lt;code&gt;Docs&lt;/code&gt;, and &lt;code&gt;Chore&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add a new release section to &lt;code&gt;CHANGELOG.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a Pull Request with that change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you configure an AI provider, it can use &lt;code&gt;OpenAI&lt;/code&gt;, &lt;code&gt;Anthropic&lt;/code&gt;, or &lt;code&gt;Gemini&lt;/code&gt; to generate a more readable changelog section.&lt;/p&gt;

&lt;p&gt;On the other hand, it also works with a fallback mode when no API key is provided.&lt;/p&gt;

&lt;p&gt;So it is totally fine even if you do not use AI.&lt;/p&gt;

&lt;p&gt;In other words, this is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A tool that can do nothing without AI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is more like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An automation tool that works better with AI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the key idea.&lt;/p&gt;




&lt;h2&gt;
  
  
  🐾 What was available up to v0.1
&lt;/h2&gt;

&lt;p&gt;Up to v0.1, I focused on building the foundation of changelog-bot.&lt;/p&gt;

&lt;p&gt;It already supported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLI and GitHub Action usage&lt;/li&gt;
&lt;li&gt;Changelog generation from Git history&lt;/li&gt;
&lt;li&gt;Importing GitHub Release Notes&lt;/li&gt;
&lt;li&gt;OpenAI and Anthropic providers&lt;/li&gt;
&lt;li&gt;Heuristic fallback&lt;/li&gt;
&lt;li&gt;Dry-run mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, the basic experience was already there:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Automatically update &lt;code&gt;CHANGELOG.md&lt;/code&gt; during a release workflow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I also introduced it in this earlier article:&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nyaomaru/generate-changelogmd-automatically-26g1" class="crayons-story__hidden-navigation-link"&gt;Generate CHANGELOG.md Automatically 🤖&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nyaomaru" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" alt="nyaomaru profile" class="crayons-avatar__image" width="800" height="790"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nyaomaru" class="crayons-story__secondary fw-medium m:hidden"&gt;
              nyaomaru
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                nyaomaru
                
                
              
              &lt;div id="story-author-preview-content-3072785" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nyaomaru" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F1436158%2Fa78bc4ed-7796-4760-baa5-06283c2404d6.png" class="crayons-avatar__image" alt="" width="800" height="790"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;nyaomaru&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nyaomaru/generate-changelogmd-automatically-26g1" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 30 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nyaomaru/generate-changelogmd-automatically-26g1" id="article-link-3072785"&gt;
          Generate CHANGELOG.md Automatically 🤖
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ci"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ci&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nyaomaru/generate-changelogmd-automatically-26g1" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;14&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nyaomaru/generate-changelogmd-automatically-26g1#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              3&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;But there were still some problems.&lt;/p&gt;

&lt;p&gt;In particular, even though users could choose an AI provider, there was still no strong way to adjust the language or writing style of the generated &lt;code&gt;CHANGELOG.md&lt;/code&gt; for each project.&lt;/p&gt;

&lt;p&gt;For example, there was no good way to pass project-specific rules such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Write it in Japanese.”&lt;/li&gt;
&lt;li&gt;“Group internal changes under Chore.”&lt;/li&gt;
&lt;li&gt;“Group dependency updates together.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the customization experience was still weak.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 v0.2: Gemini provider support
&lt;/h2&gt;

&lt;p&gt;In v0.2, I added &lt;strong&gt;Gemini&lt;/strong&gt; as a new LLM provider.&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%2Fzcjt2918edvubhn3xz4c.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%2Fzcjt2918edvubhn3xz4c.png" alt="Changelog-bot power up" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now changelog-bot supports these three providers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OpenAI&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Anthropic&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Gemini&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can specify Gemini from the CLI like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;changelog-bot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; gemini &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--release-tag&lt;/span&gt; HEAD &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--release-name&lt;/span&gt; 0.2.0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can also use it from GitHub Actions:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gemini&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GEMINI_API_KEY }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I also added &lt;strong&gt;dry-run diagnostics&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Provider: gemini
Model: gemini-3.5-flash
AI used: &lt;span class="nb"&gt;true
&lt;/span&gt;Fallback reasons: none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This makes it easier to check whether the AI provider was actually used, or whether changelog-bot fell back to the heuristic mode.&lt;/p&gt;

&lt;p&gt;It is a small feature, but I think this kind of observability is very important for CI tools.&lt;/p&gt;

&lt;p&gt;When something runs in CI, you want to quickly understand what actually happened.&lt;/p&gt;


&lt;h2&gt;
  
  
  🚀 v0.3: Changelog customization
&lt;/h2&gt;

&lt;p&gt;In v0.3, I added customization support for changelog generation.&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%2Fa126nq69tgqofz9k1uux.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%2Fa126nq69tgqofz9k1uux.png" alt="Changelog-bot note" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The newly added options are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--language&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Specifies the language of the generated &lt;code&gt;CHANGELOG.md&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--instructions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Passes inline instructions to the AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--instructions-file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Passes instructions to the AI from a file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For example, if you want to generate a changelog in Dutch, you can write:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;changelog-bot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; gemini &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--release-tag&lt;/span&gt; HEAD &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--release-name&lt;/span&gt; 0.3.0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--language&lt;/span&gt; &lt;span class="nb"&gt;nl&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--instructions&lt;/span&gt; &lt;span class="s2"&gt;"Schrijf kort en duidelijk in het Nederlands. Groepeer interne wijzigingen onder Chore."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can also define project-specific rules in a file.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;changelog-bot &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; openai &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--release-tag&lt;/span&gt; HEAD &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--release-name&lt;/span&gt; 0.3.0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--language&lt;/span&gt; &lt;span class="nb"&gt;nl&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--instructions-file&lt;/span&gt; .github/changelog-instructions.md &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For example, &lt;code&gt;.github/changelog-instructions.md&lt;/code&gt; can contain rules like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Write concise release notes in Dutch.

Rules:
&lt;span class="p"&gt;
-&lt;/span&gt; Focus on user-facing changes.
&lt;span class="p"&gt;-&lt;/span&gt; Group internal refactors under Chore.
&lt;span class="p"&gt;-&lt;/span&gt; Group dependency updates together.
&lt;span class="p"&gt;-&lt;/span&gt; Avoid mentioning commit hashes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With this, changelog-bot is no longer just “a tool that generates changelogs with AI.”&lt;/p&gt;

&lt;p&gt;It is moving toward:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A tool that can generate a &lt;code&gt;CHANGELOG.md&lt;/code&gt; that feels right for each project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also, when customization is enabled, changelog-bot does not simply use GitHub Release Notes as-is, even if they exist.&lt;/p&gt;

&lt;p&gt;Instead, it passes them to the model and lets the model rewrite them.&lt;/p&gt;

&lt;p&gt;This means GitHub Release Notes can still be used as source material, while the final output reflects the specified &lt;code&gt;language&lt;/code&gt; and &lt;code&gt;instructions&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🥌 Roadmap toward v1
&lt;/h2&gt;

&lt;p&gt;With customization added in v0.3, the shape of v1 is becoming much clearer.&lt;/p&gt;

&lt;p&gt;Here are the main things I want to add before v1.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Config file support
&lt;/h3&gt;

&lt;p&gt;Passing CLI options every time is annoying, so I want to support config files.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gemini"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"instructionsFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".github/changelog-instructions.md"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The goal is to make the same configuration usable from the CLI, GitHub Actions, and reusable workflows.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Choosing behavior when an AI provider fails
&lt;/h3&gt;

&lt;p&gt;Right now, changelog-bot falls back when an AI provider fails.&lt;/p&gt;

&lt;p&gt;This is convenient, but some projects may want the workflow to fail if AI generation fails.&lt;/p&gt;

&lt;p&gt;So I am considering options like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--fail-on-llm-error&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--require-provider&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--no-ai&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since changelog-bot is intended to be used in CI, users should be able to choose between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Fail when AI generation fails”&lt;/li&gt;
&lt;li&gt;“Fallback and continue”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both behaviors are valid depending on the project.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. JSON report output
&lt;/h3&gt;

&lt;p&gt;Dry-run diagnostics already exist, but I also want to add a JSON report.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;changelog-bot &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--report-json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For example, it would be useful to output machine-readable information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provider&lt;/li&gt;
&lt;li&gt;model&lt;/li&gt;
&lt;li&gt;aiUsed&lt;/li&gt;
&lt;li&gt;fallbackReasons&lt;/li&gt;
&lt;li&gt;generated sections&lt;/li&gt;
&lt;li&gt;PR title&lt;/li&gt;
&lt;li&gt;labels&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This should make it easier to integrate changelog-bot with other CI tools and bots.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Better changelog quality
&lt;/h3&gt;

&lt;p&gt;I also want to keep improving the quality of the generated changelog.&lt;/p&gt;

&lt;p&gt;Some areas I want to improve are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grouping dependency updates&lt;/li&gt;
&lt;li&gt;Detecting breaking changes&lt;/li&gt;
&lt;li&gt;Label-based include / exclude rules&lt;/li&gt;
&lt;li&gt;Custom section names&lt;/li&gt;
&lt;li&gt;Better duplicate detection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Especially in OSS, what should be included in a changelog differs from project to project.&lt;/p&gt;

&lt;p&gt;I want changelog-bot to handle those differences better.&lt;/p&gt;


&lt;h2&gt;
  
  
  🎯 Summary
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;CHANGELOG.md&lt;/code&gt; is a very plain file, but for users, it is an important document.&lt;/p&gt;

&lt;p&gt;Recently, it is also becoming more common to let AI read it and use it as input for dependency update decisions.&lt;/p&gt;

&lt;p&gt;That is why &lt;code&gt;CHANGELOG.md&lt;/code&gt; should not just be generated somehow.&lt;/p&gt;

&lt;p&gt;It should be generated in a readable way that fits each project’s context.&lt;/p&gt;

&lt;p&gt;But writing it carefully by hand every time is honestly a pain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nyaomaru/changelog-bot" rel="noopener noreferrer"&gt;&lt;code&gt;changelog-bot&lt;/code&gt;&lt;/a&gt; is a tool for automating that process with Git history, Pull Requests, GitHub Release Notes, and &lt;strong&gt;AI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In v0.2, I added Gemini support.&lt;/p&gt;

&lt;p&gt;In v0.3, I added customization through &lt;code&gt;language&lt;/code&gt;, &lt;code&gt;instructions&lt;/code&gt;, and &lt;code&gt;instructions file&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With these changes, changelog-bot is moving from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Just generating a changelog automatically&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generating a changelog that fits each project&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;v1 is getting closer.&lt;/p&gt;

&lt;p&gt;If you are interested, please give the repository a ⭐ and watch over it warmly!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nyaomaru" rel="noopener noreferrer"&gt;
        nyaomaru
      &lt;/a&gt; / &lt;a href="https://github.com/nyaomaru/changelog-bot" rel="noopener noreferrer"&gt;
        changelog-bot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Automatic create changelog with AI. 🤖 It provides CLI and github actions. 🚀  https://www.npmjs.com/package/&lt;a class="mentioned-user" href="https://dev.to/nyaomaru"&gt;@nyaomaru&lt;/a&gt;/changelog-bot
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/nyaomaru/changelog-bot/main/public/ChangelogBot_logo02.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fchangelog-bot%2Fmain%2Fpublic%2FChangelogBot_logo02.png" alt="changelog-bot type logo" width="360"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
    &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/nyaomaru/changelog-bot/main/public/ChangelogBot_image.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnyaomaru%2Fchangelog-bot%2Fmain%2Fpublic%2FChangelogBot_image.png" width="600px" alt="changelog-bot logo"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Releases should feel exciting, not tedious.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@nyaomaru/changelog-bot&lt;/code&gt; 🤖 turns your Git history and release notes into a polished changelog entry (and optional PR) in a single run. Drop it into CI, run it locally, or hand it to your release captain—either way, you ship with a crisp changelog and zero copy-paste fatigue.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why changelog-bot?&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automated storytelling:&lt;/strong&gt; Combines commit history, PR titles, and release notes to produce human-ready changelog sections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM superpowers (optional):&lt;/strong&gt; Connect OpenAI or Anthropic for tone-aware summaries or skip API keys entirely and rely on a robust heuristic fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PR-ready output:&lt;/strong&gt; Can open a pull request with updated changelog, compare links, and release notes already wired up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe defaults:&lt;/strong&gt; Detects duplicate versions, keeps compare links current, and won’t fail a release if AI is down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI-native:&lt;/strong&gt; Works as a GitHub Action, reusable workflow, or plain CLI—no fragile scripting required.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-alert markdown-alert-important"&gt;
&lt;p class="markdown-alert-title"&gt;Important&lt;/p&gt;
&lt;p&gt;This project is currently in its early stages…&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nyaomaru/changelog-bot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Now let’s auto-generate our &lt;code&gt;CHANGELOG.md&lt;/code&gt; files and use the saved time to play some games! 🧟🍀&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>opensource</category>
      <category>changelog</category>
      <category>githubactions</category>
    </item>
  </channel>
</rss>
