<?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>Forem: Keyur Paralkar</title>
    <description>The latest articles on Forem by Keyur Paralkar (@keyurparalkar).</description>
    <link>https://forem.com/keyurparalkar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F470219%2F7e0d78ea-4cd1-42ac-9911-3be6dff09db4.jpg</url>
      <title>Forem: Keyur Paralkar</title>
      <link>https://forem.com/keyurparalkar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/keyurparalkar"/>
    <language>en</language>
    <item>
      <title>Adding Rows &amp; Columns</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Sun, 01 Mar 2026 16:03:04 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/building-a-production-grade-table-editor-with-react-and-xstate-adding-rows-columns-efb</link>
      <guid>https://forem.com/keyurparalkar/building-a-production-grade-table-editor-with-react-and-xstate-adding-rows-columns-efb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the previous blogpost, we build a table editor that used xstate’s state machine. We managed to build a schema driven architecture where schema was the source of truth for rendering things on the table-editor.&lt;/p&gt;

&lt;p&gt;This blog post continues the same architecture and focuses on building a feature that will help to add a row and column into the table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Addition of Row/Column
&lt;/h2&gt;

&lt;p&gt;Our table editor in the current state, is just a basic table that loads some defaults. Now let us try to make it interactive by introducing addition of row and column.&lt;/p&gt;

&lt;p&gt;The experience we are targeting should be such that it requires minimal effort for the user to add a row or a column into the table. I really liked notion’s UX of addition row and column:&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%2Fke3xrxtq0qurwto3fub8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fke3xrxtq0qurwto3fub8.gif" alt="Image_description" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on the similar lines we will also be building a similar UX for our table-editor. I have already implemented it and here is how it looks:&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%2Fpckzhpqq37xlaoh31apl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpckzhpqq37xlaoh31apl.gif" alt="image_des" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the things we need to achieve this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change in state machine for addition of row/column&lt;/li&gt;
&lt;li&gt;Handler UI around the right and bottom of the table editor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡&lt;/p&gt;

&lt;p&gt;If you are a first time reader, I would highly recommend to please go through the first blogpost of this series that talks about how the xstate machine &amp;amp; the schema.&lt;/p&gt;

&lt;p&gt;Let us first start by understand the things we need to change in state machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  State Machine changes
&lt;/h3&gt;

&lt;p&gt;Conceptually, adding a row/column can be reduced to four deterministic steps:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;User clicks the row/column handlebar&lt;/code&gt; → &lt;code&gt;Send Row/Column addition event to machine&lt;/code&gt; → &lt;code&gt;Machine Updates Schema&lt;/code&gt; → &lt;code&gt;UI renders new schema&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These four steps are all it takes to build this feature. Let’s dive deeper into each of these steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User clicks the row/column handlerbar&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is basically building the UI for the user to interact with. We will look at in depth in the next section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Send Row/Column addition event to machine &amp;amp; Schema update&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My thought process here is to introduce entities to table. Entities are nothing but objects that impact the table editor’s state. There can be multiple types of entities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Table Entities: They deal with structural changes to the editor's state like add, removing, resizing, etc of rows &amp;amp; columns&lt;/li&gt;
&lt;li&gt;Cell entities: They deal with the structural changes related to cell&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In case of this feature we are trying to add an entity i.e. row/column. So I introduced a new event named: &lt;code&gt;add.table.entities&lt;/code&gt;. This event will be watched when you are in the &lt;code&gt;ready&lt;/code&gt; state of the machine.&lt;/p&gt;

&lt;p&gt;So now our state machine’s states will look:&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nl"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;always&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;actions&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;initTable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&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;ready&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;on&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;add.table.entities&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;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addingTableEntities&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the user interacts with the handlebars they will send the machine these events in the following manner:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleAddColumn&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;send&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;add.table.entities&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;payload&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;col&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleAddRow&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;send&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;add.table.entities&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;payload&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;row&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While sending the event we tell what type of entity we are trying to add here it is &lt;code&gt;row&lt;/code&gt; / &lt;code&gt;col&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When the machine receives this event, it transitions to &lt;code&gt;addingTableEntities&lt;/code&gt;. This is another state that will have the following responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deciding the the type of entity to add.&lt;/li&gt;
&lt;li&gt;Add the entity&lt;/li&gt;
&lt;li&gt;Return back to the ready state.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/**
         * The task of this state is to initialize the table with default no. of rows and columns
         * which is passed as an input to this machine
         */&lt;/span&gt;
        &lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;always&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;actions&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;initTable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&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="na"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;on&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;add.table.entities&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;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addingTableEntities&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="cm"&gt;/**
         * Entities are objects that impact the table editor's state.
         * There are multiple types of entities:
         * - Table entities - They deal with structural changes to the editor's state like add, removing, resizing, etc rows &amp;amp; cols.
         * - Cell entities - They deal with the structural changes related to cell
         */&lt;/span&gt;
        &lt;span class="na"&gt;addingTableEntities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decideOp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;states&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;decideOp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;always&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;guard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isAddingRow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addingRow&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="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addingCol&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;addingRow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;always&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;actions&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;addRow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complete&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="na"&gt;addingCol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;always&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;actions&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;addCol&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complete&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="na"&gt;complete&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;final&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="na"&gt;onDone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#table-editor-machine.ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;addingTableEntities&lt;/code&gt; is a &lt;a href="https://stately.ai/docs/glossary#parent-and-child-states" rel="noopener noreferrer"&gt;compound state&lt;/a&gt; which means having child states. Let me explain to you what the &lt;code&gt;addingTableEntities&lt;/code&gt; state is doing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When this state becomes active from the &lt;code&gt;add.table.entities&lt;/code&gt; event, it imimediately gets into the &lt;code&gt;decideOp&lt;/code&gt; initial state.&lt;/li&gt;
&lt;li&gt;When in &lt;code&gt;decideOp&lt;/code&gt;, we determine if its a row addition operation by checking the guard:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;  &lt;span class="nx"&gt;guards&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;isAddingRow&lt;/span&gt;&lt;span class="p"&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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;row&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;If &lt;code&gt;true&lt;/code&gt;, it transitions to &lt;code&gt;addingRow&lt;/code&gt; state else fallbacks to the &lt;code&gt;addingCol&lt;/code&gt; state.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both &lt;code&gt;addingRow&lt;/code&gt; / &lt;code&gt;addingCol&lt;/code&gt; are exactly the same &lt;a href="https://stately.ai/docs/eventless-transitions" rel="noopener noreferrer"&gt;eventless transition&lt;/a&gt; states. They both point to the same target state: &lt;code&gt;complete&lt;/code&gt;. They just differ by actions: &lt;code&gt;addRow&lt;/code&gt; / &lt;code&gt;addCol&lt;/code&gt;. Both of these actions only do the following thing: &lt;em&gt;Update the schema by appending a new row/column into the rowOrder/colOrder and their property configs rowsById/colsById:&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;  &lt;span class="nx"&gt;addRow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draftSchema&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;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowOrder&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;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowOrder&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="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

                    &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowsById&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;len&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&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;draftSchema&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;rO&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="cm"&gt;/**
                         * Use the colOrder from original context rather than draftContext
                         * because rowOrder is the one that is getting changed and colOrder remains unchanged.
                         */&lt;/span&gt;
                        &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cO&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;cellKey&lt;/span&gt; &lt;span class="o"&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;rO&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;cO&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;MachineContext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schema&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;cells&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

                            &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cellKey&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="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;empty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;value&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="p"&gt;};&lt;/span&gt;
                        &lt;span class="p"&gt;});&lt;/span&gt;
                    &lt;span class="p"&gt;});&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="nx"&gt;addCol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draftSchema&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;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colOrder&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;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colOrder&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="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

                    &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colsById&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;len&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;len&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="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;};&lt;/span&gt;

                    &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;rO&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="cm"&gt;/**
                         * Use the rowOrder from original context rather than draftContext
                         * because colOrder is the one that is getting changed and colOrder remains unchanged.
                         */&lt;/span&gt;
                        &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cO&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;cellKey&lt;/span&gt; &lt;span class="o"&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;rO&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;cO&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;MachineContext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schema&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;cells&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

                            &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cellKey&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="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;empty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;value&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="p"&gt;};&lt;/span&gt;
                        &lt;span class="p"&gt;});&lt;/span&gt;
                    &lt;span class="p"&gt;});&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The last state is the &lt;code&gt;complete&lt;/code&gt; state with the &lt;code&gt;type: :"final"&lt;/code&gt;. This tells the machine that the operation has completed and no further transitions should occur within this branch.
Once this state is reached we transition to the parent state from the child state i.e. &lt;code&gt;complete&lt;/code&gt; state → &lt;code&gt;addingTableEntities&lt;/code&gt; state.&lt;/li&gt;
&lt;li&gt;Now our aim is to get back to the &lt;code&gt;ready&lt;/code&gt; state when reach the &lt;code&gt;complete&lt;/code&gt; state. Since &lt;code&gt;complete&lt;/code&gt; state is of &lt;code&gt;type: :"final"&lt;/code&gt;, and when it is reached it fires the &lt;code&gt;onDone&lt;/code&gt; &lt;a href="https://stately.ai/docs/state-done-events" rel="noopener noreferrer"&gt;state done event&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;  &lt;span class="nx"&gt;onDone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nl"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#table-editor-machine.ready&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;In this transition we tell to redirect us to the ready state of the machine.&lt;/p&gt;

&lt;p&gt;Once this transition is done the schema gets updated and the table-editor component picks up the new values and renders the same.&lt;/p&gt;

&lt;p&gt;You might wonder — why not directly handle &lt;code&gt;add.table.entities&lt;/code&gt; with an action inside ready? Because I want structural mutations to be explicit states, not invisible side-effects.&lt;/p&gt;

&lt;p&gt;By introducing &lt;code&gt;addingTableEntities&lt;/code&gt; as a compound state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structural transitions become traceable&lt;/li&gt;
&lt;li&gt;Future logic can hook into this state&lt;/li&gt;
&lt;li&gt;The machine remains extensible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let us look at those UI handlebars that we were talking about in the earlier section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handler-bars UI around the table editor
&lt;/h3&gt;

&lt;p&gt;The last piece of the code, is to create the UI that facilitates this addition of row and column. At the start of the blog we decided to make use of the notion’s user experience of having handle bars to the right and bottom of the table editor. We will be doing the same thing.&lt;/p&gt;

&lt;p&gt;This piece of code add these handles to the main table-editor component hence here is the updated table-editor component:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TableEditor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;defaultColumns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultRows&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;TableEditorProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actorRef&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMachine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TableEditorMachine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;defaultColumns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;defaultRows&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="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getCellKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getCellProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getColumnProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getRowProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGetTableProperties&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;actorRef&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;handleAddColumn&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;send&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;add.table.entities&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;payload&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;col&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleAddRow&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;send&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;add.table.entities&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;payload&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;row&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"inline-block relative"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GridRow&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getColumnProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GridHeader&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border"&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                                    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GridHeader&lt;/span&gt;&lt;span class="p"&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="si"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GridRow&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getRowProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GridRow&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="si"&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;rest&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&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;cellKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCellKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&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;key&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="nx"&gt;rest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCellProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cellKey&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GridCell&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border"&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;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="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GridCell&lt;/span&gt;&lt;span class="p"&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="si"&gt;}&lt;/span&gt;
                            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GridRow&lt;/span&gt;&lt;span class="p"&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="si"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/** Handle bars for add rows/columns */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
                &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"table-handlebar-col"&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"transition-all opacity-0 hover:opacity-100 hover:bg-gray-300/30 rounded h-full w-5 absolute top-0 left-full ml-2 flex flex-col justify-center items-center cursor-pointer"&lt;/span&gt;
                &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleAddColumn&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 select-none"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
                &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"table-handlebar-row"&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"transition-all opacity-0 hover:opacity-100 hover:bg-gray-300/30 rounded h-6 w-full absolute left-0 mt-2 flex justify-center items-center cursor-pointer"&lt;/span&gt;
                &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleAddRow&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 select-none"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&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 is how our new handlebars will look like:&lt;/p&gt;

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

&lt;p&gt;In the next article, we’ll tackle one of the hardest problems in table editors: selection.&lt;/p&gt;

&lt;p&gt;And this is where things start to get interesting.&lt;/p&gt;

&lt;p&gt;Hope you like my blog post.&lt;/p&gt;

&lt;p&gt;You can follow me on &lt;a href="https://twitter.com/keurplkar" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar" rel="noopener noreferrer"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/" rel="noopener noreferrer"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>react</category>
      <category>typescript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Building a Production-Grade Table Editor with React and XState</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Sun, 22 Feb 2026 13:36:06 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/building-a-production-grade-table-editor-with-react-and-xstate-41ke</link>
      <guid>https://forem.com/keyurparalkar/building-a-production-grade-table-editor-with-react-and-xstate-41ke</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

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

&lt;p&gt;Add rows. Edit cells. Resize columns. &lt;/p&gt;

&lt;p&gt;But once you add undo/redo, reordering, grouping, and consistent UI feedback — the logic becomes chaotic.&lt;/p&gt;

&lt;p&gt;In this series, we’ll build a production-grade table editor using a state machine approach with XState.&lt;/p&gt;

&lt;h2&gt;
  
  
  What
&lt;/h2&gt;

&lt;p&gt;Have you ever used SaaS products that have a great table editing and viewing experience. Let me give you some examples:&lt;/p&gt;

&lt;h3&gt;
  
  
  Clay
&lt;/h3&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%2F8dc93sfgdziqu4f78i4h.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%2F8dc93sfgdziqu4f78i4h.png" alt="Image description_" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Notion
&lt;/h3&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%2F3wwy2i1xvjcdtcn21f4f.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%2F3wwy2i1xvjcdtcn21f4f.png" alt="Image description_" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy7xvpq12cdy3cpwuk3e.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%2Fvy7xvpq12cdy3cpwuk3e.png" alt="Image description_" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Sheets
&lt;/h3&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%2F3hnlhi1274yfu0m3r7n9.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%2F3hnlhi1274yfu0m3r7n9.png" alt="Image description_" width="800" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifacb97j9e13bp94qy4x.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%2Fifacb97j9e13bp94qy4x.png" alt="Image description_" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They are just easy to navigate, put your data and you are done. It just feels natural and provides consistent feedback on every operation we do in these tables.&lt;/p&gt;

&lt;p&gt;So in this blogpost series we will be looking at how to create your own table editor which provides an experience like these products. Especially we will try to implement features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Row and column addition and deletion&lt;/li&gt;
&lt;li&gt;Re-ordering of columns and rows&lt;/li&gt;
&lt;li&gt;Re-sizing of rows and columns&lt;/li&gt;
&lt;li&gt;Grouping Rows and columns&lt;/li&gt;
&lt;li&gt;Table editing experience.&lt;/li&gt;
&lt;li&gt;Undo - redo operations&lt;/li&gt;
&lt;li&gt;etc….&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;This series is not about competing with existing table libraries. It’s about understanding how production-grade data editors are architected.&lt;/p&gt;

&lt;p&gt;When you understand the underlying model — schema normalization, state orchestration, transactional updates — you can design better systems everywhere else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To understand this blogpost series you need some basic understanding of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XState:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stately.ai/docs/state-machines-and-statecharts" rel="noopener noreferrer"&gt;Core concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stately.ai/docs/machines" rel="noopener noreferrer"&gt;State machines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stately.ai/docs/quick-start" rel="noopener noreferrer"&gt;Building you first state machine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Typescript&lt;/li&gt;

&lt;li&gt;React&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  How
&lt;/h2&gt;

&lt;p&gt;We won’t be building all these features in this blogpost itself. That would be foolish 😀. We will start by a simple setting up of the project + designing the basic architecture of our table-editor component. &lt;/p&gt;

&lt;p&gt;Here are the things we need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A simple react vite project. You can follow the vite’s official guide to setup your first react project with typescript template here&lt;/li&gt;
&lt;li&gt;Install the xState library by following the instructions here.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The architecture of our table-editor can be understood in the following parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Schema&lt;/li&gt;
&lt;li&gt;State Machine&lt;/li&gt;
&lt;li&gt;Editor Component&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Schema
&lt;/h3&gt;

&lt;p&gt;We don’t want a complex web of useStates to manage the actual state of our component. We want it to be clear, precise, reliable and robust. To achieve this we need a reliable architecture that will scale better with the new feature. We achieve this with the help of schema.&lt;/p&gt;

&lt;p&gt;A schema is nothing but a big JS Object that acts as a single source of truth for the table editor. This would be the source of whatever you see and happens to the table editor. For example, if you try to add a column or row then first it will be updated in the schema → And then all the subscribed components would derive their states from the schema’s current state.&lt;/p&gt;

&lt;p&gt;Why to choose this pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Represents the current state of the table.&lt;/li&gt;
&lt;li&gt;Provides better developer experience.&lt;/li&gt;
&lt;li&gt;Makes the table robust.&lt;/li&gt;
&lt;li&gt;Errors can be caught pretty easily&lt;/li&gt;
&lt;li&gt;Scalable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let us start first by looking at the schema with actual values in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cId1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cId2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rId1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rId2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;

    &lt;span class="na"&gt;colsById&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;cId1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cId1&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;col 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;style&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;cId2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cId2&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;col 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;style&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="na"&gt;rowsById&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;rId1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rId1&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;row 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;style&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;rId2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rId2&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;row 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;style&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="na"&gt;cells&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;rId1:cId1&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;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;empty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;value&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rId1:cId2&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;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;empty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;value&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rId2:cId1&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;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;empty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;value&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rId2:cId2&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;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;empty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;value&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="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;Above represents a 2x2 table i.e. with 2 rows and 2 columns. The picture will be much clearer when we look at the typescript schema for the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CSSProperties&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;react&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="nx"&gt;type&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CSSProperties&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;export&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Column&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;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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CSSProperties&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;export&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RowId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ColumnId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CellKey&lt;/span&gt; &lt;span class="o"&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;RowId&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;ColumnId&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;type&lt;/span&gt; &lt;span class="nx"&gt;CellValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&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;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;kind&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="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&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="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;empty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nl"&gt;value&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="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CellMeta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CSSProperties&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&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;height&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="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Cell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CellValue&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;CellMeta&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ColumnId&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;rowOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RowId&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;colsById&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ColumnId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Column&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;rowsById&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RowId&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="p"&gt;;&lt;/span&gt;

    &lt;span class="nl"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CellKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Cell&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;A schema is represented above typescript types. Let me briefly describe these types for your:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Every schema is composed of the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;colOrder&lt;/code&gt; - These are the orders that user sees on the UI for columns. From the above example, when this order is = &lt;code&gt;[cId1, cId2]&lt;/code&gt; that means that &lt;code&gt;cId1&lt;/code&gt; appears before &lt;code&gt;cId2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rowOrder&lt;/code&gt; - This is exactly similar to that of the &lt;code&gt;colOrder&lt;/code&gt; but for rows.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;colsById&lt;/code&gt; - This is a object where key is the column’s id and value is the properties that define that column. So this is an object which provides all the information about a column when you query it by id.&lt;/p&gt;

&lt;p&gt;Every value is of type &lt;code&gt;Column&lt;/code&gt; which defines the structure of the given column. A single &lt;code&gt;Column&lt;/code&gt; can have the following properties: &lt;code&gt;id&lt;/code&gt; &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;style&lt;/code&gt;. Thus defining the characteristics of a column.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;rowsById&lt;/code&gt; - Exactly similar to &lt;code&gt;colsById&lt;/code&gt; but for rows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;cells&lt;/code&gt; - This is again an object which can be used to get the properties of each individual cell. If you want to get information about a cell you should query it by &lt;code&gt;CellKey&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CellKey&lt;/code&gt; is represented by &lt;code&gt;&amp;lt;row-id&amp;gt;:&amp;lt;col-id&amp;gt;&lt;/code&gt;. Every &lt;code&gt;CellKey&lt;/code&gt; represents a &lt;code&gt;Cell&lt;/code&gt; which defines the characteristics just as the above &lt;code&gt;Column&lt;/code&gt; and &lt;code&gt;Row&lt;/code&gt; types. Please have a look at them above in the TS types.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Now the question arises as to why we did we design schema with this approach? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This schema is normalized.&lt;/li&gt;
&lt;li&gt;It separates structure from order.&lt;/li&gt;
&lt;li&gt;It prevents expensive array traversal.&lt;/li&gt;
&lt;li&gt;It scales to thousands of rows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;Schema&lt;/code&gt; is designed in this way to provide maximum scaleability and maintainability with the help of separation of concerns. This is achieved by keeping the order related stuff that the user would see in the separate array i.e. &lt;code&gt;rowOrder&lt;/code&gt; &lt;code&gt;colOrder&lt;/code&gt; and information about each of this row and column in the &lt;code&gt;rowsById&lt;/code&gt; and &lt;code&gt;colsById&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now changing the order would simply mean changing the position of row ids in the &lt;code&gt;rowOrder&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;If you want to update the characteristics of a specific row then you can do so by changing the row’s value from the &lt;code&gt;rowsById&lt;/code&gt; mapping.&lt;/p&gt;

&lt;p&gt;Let me explain you this by an example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Consider that the above schema would have been represented in the following manner:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;Schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Column&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you wanted to change the position of a row, then you need to do the following things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First find the row.&lt;/li&gt;
&lt;li&gt;Take the row&lt;/li&gt;
&lt;li&gt;Put it at the correct place that you want&lt;/li&gt;
&lt;li&gt;re-index the id property of the entire array.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Now also consider that you wanted to change the background color of the row:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Again we find the row&lt;/li&gt;
&lt;li&gt;Update the background property in the styles&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;But with the current i.e. the split approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It simplifies updates&lt;/li&gt;
&lt;li&gt;It avoids unnecessary object recreation&lt;/li&gt;
&lt;li&gt;It enables partial updates&lt;/li&gt;
&lt;li&gt;It keeps reordering separate from mutation&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%2Fxcnokqked8rqbc100y8a.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%2Fxcnokqked8rqbc100y8a.png" alt="Image description_" width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think of this schema like a normalized database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rowOrder&lt;/code&gt; is the index&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rowsById&lt;/code&gt; is the table&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cells&lt;/code&gt; is a join table between rows and columns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have a normalized data model, we need a way to orchestrate how it changes over time.&lt;/p&gt;

&lt;p&gt;That’s where state machines come in.&lt;/p&gt;

&lt;h3&gt;
  
  
  State Machine
&lt;/h3&gt;

&lt;p&gt;State machine is a model that will help you organise complex state logic that you have in your component, app etc. It does that by defining:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;States&lt;/li&gt;
&lt;li&gt;Events&lt;/li&gt;
&lt;li&gt;Transitions&lt;/li&gt;
&lt;li&gt;Side effects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of scattering logic across multiple &lt;code&gt;useState&lt;/code&gt; hooks, we centralize behavior inside a predictable model.&lt;/p&gt;

&lt;p&gt;For our table editor, we’ll use Stately’s library XState to orchestrate the editor logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Machine Overview&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The flow of our table editor is quite simple. There are two of states to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;init&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ready&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conceptually, it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbk51rduvbaynv5d459vh.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%2Fbk51rduvbaynv5d459vh.png" alt="Image description_" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Happens During Initialization?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It enters into the &lt;code&gt;init&lt;/code&gt; state&lt;/li&gt;
&lt;li&gt;It generates the initial schema based on input (&lt;code&gt;defaultRows&lt;/code&gt;, &lt;code&gt;defaultColumns&lt;/code&gt;) i.e. the defaults we pass to the machine&lt;/li&gt;
&lt;li&gt;It transitions to &lt;code&gt;ready&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a quick look at how our table will look like with this state machine when loaded with defaults: &lt;code&gt;rows = 4&lt;/code&gt; &amp;amp; &lt;code&gt;cols = 3&lt;/code&gt; :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmnb8vcvpyj5vaqmczlka.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%2Fmnb8vcvpyj5vaqmczlka.png" alt="Image description_" width="628" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Machine Definition&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is the actual XState state machine that wraps the above logical flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TableEditorMachine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;context&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;MachineContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;MachineInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;initTable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draftSchema&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="cm"&gt;/**
                     * This is where the magic happens:
                     * - We create a rowOrder and ColumnOrder by filling it with ids. At the current moment they can be indices
                     * - Then we fill up the colsByID and rowsById objects
                     * - Then we fill up cells with empty states
                     */&lt;/span&gt;

                    &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowOrder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&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;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colOrder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;)&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&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;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowsById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;curr&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;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;curr&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;curr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&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;acc&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;as&lt;/span&gt; &lt;span class="nx"&gt;MachineContext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schema&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;rowsById&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;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colsById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;curr&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;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;curr&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;curr&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="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="p"&gt;},&lt;/span&gt;
                            &lt;span class="p"&gt;};&lt;/span&gt;

                            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;acc&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;as&lt;/span&gt; &lt;span class="nx"&gt;MachineContext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schema&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;colsById&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="cm"&gt;/**
                     * We define cells as well:
                     */&lt;/span&gt;
                    &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;rO&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;draftSchema&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cO&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;cellKey&lt;/span&gt; &lt;span class="o"&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;rO&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;cO&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;MachineContext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schema&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;cells&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

                            &lt;span class="nx"&gt;draftSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cellKey&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="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;empty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;value&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="p"&gt;};&lt;/span&gt;
                        &lt;span class="p"&gt;});&lt;/span&gt;
                    &lt;span class="p"&gt;});&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;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="nf"&gt;createMachine&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;table-editor-machine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;rows&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="nx"&gt;defaultRows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;columns&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="nx"&gt;defaultColumns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
            &lt;span class="na"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;

            &lt;span class="na"&gt;colsById&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
            &lt;span class="na"&gt;rowsById&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;

            &lt;span class="na"&gt;cells&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="na"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;init&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;states&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/**
         * The task of this state is to initialize the table with default no. of rows and columns
         * which is passed as an input to this machine
         */&lt;/span&gt;
        &lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;always&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;actions&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;initTable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&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="na"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this machine is doing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s break this machine down clearly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The machine accepts input:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;rows&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="nx"&gt;defaultRows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;columns&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="nx"&gt;defaultColumns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This ensures that the machine is initialized with the required inputs. These inputs will be used to generate the defaults in the schema.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;init&lt;/code&gt; State Performs an Eventless Transition:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;always&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;actions&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;initTable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&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;ul&gt;
&lt;li&gt;Here no event is required.&lt;/li&gt;
&lt;li&gt;Execute the action &lt;code&gt;initTable&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;On action complete move to &lt;code&gt;ready&lt;/code&gt; state.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;initTable&lt;/code&gt; action builds the entire schema with defaults by doing the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates ordered row IDs&lt;/li&gt;
&lt;li&gt;Creates ordered column IDs&lt;/li&gt;
&lt;li&gt;Populates &lt;code&gt;rowsById&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Populates &lt;code&gt;colsById&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Generates every cell key (&lt;code&gt;rowId:colId&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All mutations above are handled with immutably using &lt;code&gt;produce&lt;/code&gt; (Immer).&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The important thing to note here is that: &lt;code&gt;The schema is generated **inside the machine**, not inside React&lt;/code&gt;. This means that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initialization logic is centralized.&lt;/li&gt;
&lt;li&gt;It is testable.&lt;/li&gt;
&lt;li&gt;It is deterministic.&lt;/li&gt;
&lt;li&gt;It is independent from rendering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why this matters and what it means?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even though our machine is small, this structure gives us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A predictable lifecycle&lt;/li&gt;
&lt;li&gt;A single place for orchestration&lt;/li&gt;
&lt;li&gt;A scalable foundation for future features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Row insertion&lt;/li&gt;
&lt;li&gt;Column resizing&lt;/li&gt;
&lt;li&gt;Undo/redo&lt;/li&gt;
&lt;li&gt;Reordering&lt;/li&gt;
&lt;li&gt;Grouping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We won’t mutate React state directly. Rather we will send events to this machine. That’s the real power of this approach. The machine owns orchestration. React only renders.&lt;/p&gt;

&lt;p&gt;React becomes a rendering layer. The machine becomes the source of truth.&lt;/p&gt;

&lt;p&gt;Now that we know how the machine works and the importance of this approach, let us understand how can you hook this with your react code. &lt;/p&gt;

&lt;h3&gt;
  
  
  Table Editor
&lt;/h3&gt;

&lt;p&gt;Before we start hooking the machine let us first create these building blocks to create a table:  &lt;code&gt;td&lt;/code&gt; &lt;code&gt;th&lt;/code&gt;  &lt;code&gt;tr&lt;/code&gt; :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;td&lt;/code&gt;:&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="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CSSProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PropsWithChildren&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;react&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;GridCellProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;className&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;style&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;CSSProperties&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;GridCell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;GridCellProps&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="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;GridCell&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;th&lt;/code&gt;:&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="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CSSProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PropsWithChildren&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;react&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;GridHeaderProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;className&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;style&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;CSSProperties&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;GridHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;GridHeaderProps&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="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="si"&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;rest&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;GridHeader&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;tr&lt;/code&gt;:&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="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CSSProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PropsWithChildren&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;react&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;GridRowProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;className&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;style&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;CSSProperties&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;GridRow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;GridRowProps&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="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;GridRow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can even use any component library you want, just make sure to pass the props correctly.&lt;/p&gt;

&lt;p&gt;Here is a custom hook that will help us to get table properties from our machine:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UseGetTablePropertiesProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;actorRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActorRefFrom&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;TableEditorMachine&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="cm"&gt;/**
 * A hook that provides helper functions for extracting properties from entities like col, row and cells
 */&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;useGetTableProperties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;actorRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;UseGetTablePropertiesProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;colsById&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rowsById&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cells&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;actorRef&lt;/span&gt;&lt;span class="p"&gt;,&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="o"&gt;=&amp;gt;&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;schema&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;getColumnProperties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;colId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ColumnId&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;columnProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;colsById&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;colId&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;columnProps&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`col-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;data-col-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;style&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;getRowProperties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;rowId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RowId&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;rowProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rowsById&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rowId&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rowProps&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`row-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;style&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;getCellKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;rowId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RowId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;colId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ColumnId&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;CellKey&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;rowId&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;colId&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCellProperties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;cellKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CellKey&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;cellProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cellKey&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;kind&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;style&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cellProps&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cellKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cellKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;kind&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;style&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="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;colsById&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;rowsById&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getCellKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getCellProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getColumnProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getRowProperties&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;Let me describe this hook briefly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It takes input as &lt;code&gt;actorRef&lt;/code&gt; which is a reference to our state machine.&lt;/li&gt;
&lt;li&gt;Now to access the context that we had in our machine we use the XState’s &lt;a href="https://stately.ai/docs/xstate-react#useselectoractorref-selector-compare-getsnapshot" rel="noopener noreferrer"&gt;&lt;code&gt;useSelector&lt;/code&gt; hook&lt;/a&gt; &lt;a href="https://stately.ai/docs/xstate-store/react#useselectorstore-selector-compare" rel="noopener noreferrer"&gt;&lt;/a&gt;to get all the properties we need. You can get all the information you need from the machine. You just need to tell the selector that you need information via this piece of code: &lt;code&gt;(s) =&amp;gt; s.context.schema&lt;/code&gt;. Since this is the information that we need i.e. source of truth to render the UI.&lt;/li&gt;
&lt;li&gt;This hook exposes other helper functions: &lt;code&gt;getColumnProperties&lt;/code&gt; &lt;code&gt;getRowProperties&lt;/code&gt; and &lt;code&gt;getCellKey&lt;/code&gt; &lt;code&gt;getCellProperties&lt;/code&gt; and other variables. The functions here provides you the meta data about a row, column or a cell via providing them row, col and cell id. This makes it easier in the rendering part to render the UI elements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;useSelector&lt;/code&gt; ensures that the component only re-renders when the selected part of the machine changes.&lt;/p&gt;

&lt;p&gt;Now let us create a &lt;code&gt;table-editor&lt;/code&gt; component that will hook all of the above things:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TableEditor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;defaultColumns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultRows&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;TableEditorProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actorRef&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMachine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TableEditorMachine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;defaultColumns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;defaultRows&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="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getCellKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getCellProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getColumnProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;getRowProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGetTableProperties&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;actorRef&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"inline-block relative"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GridRow&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getColumnProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GridHeader&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border"&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                                    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GridHeader&lt;/span&gt;&lt;span class="p"&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="si"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GridRow&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rowOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getRowProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GridRow&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="si"&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;rest&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;colOrder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&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;cellKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCellKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&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;key&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="nx"&gt;rest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCellProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cellKey&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GridCell&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border"&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;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="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GridCell&lt;/span&gt;&lt;span class="p"&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="si"&gt;}&lt;/span&gt;
                            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GridRow&lt;/span&gt;&lt;span class="p"&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="si"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&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;This is a pretty simple component and it does the following things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes use of &lt;code&gt;useMachine&lt;/code&gt; that takes our machine &lt;code&gt;TableEditorMachine&lt;/code&gt; as the input. In this hook we also pass the arguments which acts as an input to our machine i.e. &lt;code&gt;defaultColumns&lt;/code&gt; and &lt;code&gt;defaultRows&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We pass the machine’s reference &lt;code&gt;actorRef&lt;/code&gt; to the our custom hook &lt;code&gt;useGetTableProperties&lt;/code&gt; to get the table properties.&lt;/li&gt;
&lt;li&gt;Lastly we loop over the row and column order and use the building blocks that we created to render each table property.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next article, we’ll implement row and column insertion — not as ad-hoc mutations, but as state machine transitions.&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%2Fio7tbpy7k14d7u9z6g0n.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fio7tbpy7k14d7u9z6g0n.gif" alt="Image description_" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope you like my blog post.&lt;/p&gt;

&lt;p&gt;You can follow me on &lt;a href="https://twitter.com/keurplkar" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar" rel="noopener noreferrer"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/" rel="noopener noreferrer"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>architecture</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Hey folks, I wrote about website localization and its importance. Do give it a read!</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Sun, 15 Dec 2024 08:19:29 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/hey-folks-i-wrote-about-website-localization-and-its-importance-do-give-it-a-read-nfd</link>
      <guid>https://forem.com/keyurparalkar/hey-folks-i-wrote-about-website-localization-and-its-importance-do-give-it-a-read-nfd</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/keyurparalkar" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2F470219%2F7e0d78ea-4cd1-42ac-9911-3be6dff09db4.jpg" alt="keyurparalkar"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/keyurparalkar/what-is-website-localization-55mn" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;What is Website Localization?&lt;/h2&gt;
      &lt;h3&gt;Keyur Paralkar ・ Nov 25&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#learning&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>What is Website Localization?</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Mon, 25 Nov 2024 17:44:11 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/what-is-website-localization-55mn</link>
      <guid>https://forem.com/keyurparalkar/what-is-website-localization-55mn</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Have you ever seen some advertisements that are catered around your current trends? For example, Spotify understanding the current trends of the youth and displaying ads like this classic: &lt;em&gt;group of friends always plan a long trip but it always remain in the chats 😀&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ferz3pltl1fo7gf5kd0kx.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%2Ferz3pltl1fo7gf5kd0kx.png" alt="Spotify ads" width="735" height="770"&gt;&lt;/a&gt;Spotify ads
  

&lt;/p&gt;

&lt;p&gt;Or you might have seen google’s sign in page in different languages:&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%2F7yzzqx5anvp3fvanfbrr.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%2F7yzzqx5anvp3fvanfbrr.png" alt="Google Sign-in page in English" width="800" height="386"&gt;&lt;/a&gt;Google Sign-in page in English
  

&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%2F77rvap2wmsob9bw36zi4.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%2F77rvap2wmsob9bw36zi4.png" alt="Google Sign-in page in German" width="800" height="386"&gt;&lt;/a&gt;Google Sign-in page in German
  

&lt;/p&gt;

&lt;p&gt;Here is another example of the famous brand: IKEA. They use localization heavily to create unique experience. For example, IKEA’s main idea was to sell furniture which can be assembled at home with their instruction manual. This is a good approach in most of the countries but in China assembling the furniture is considered to be an opposite symbol. They prefer furniture to be assembled by some handyman or a third party service. &lt;/p&gt;

&lt;p&gt;IKEA was left to either provide assembly service as well or leave the China market. IKEA took the first approach and introduced assembly service specific to China. This helped them to increase their market hold there by multiple folds. &lt;/p&gt;

&lt;p&gt;You can see this experience on IKEA’s website, here is a quick look of India and China version of the website&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%2Fuqdr9fhm0r8n56vu9506.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%2Fuqdr9fhm0r8n56vu9506.png" alt="Ikea showing no assembly service option for India region" width="800" height="505"&gt;&lt;/a&gt;Ikea showing no assembly service option for India region
  

&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%2Fbyig8g6hfxz3w1lu3yyg.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%2Fbyig8g6hfxz3w1lu3yyg.png" alt="Assembly service option at the bottom left for China region" width="800" height="586"&gt;&lt;/a&gt;Assembly service option at the bottom left for China region
  

&lt;/p&gt;

&lt;p&gt;This example was inspired from &lt;a href="https://www.oneskyapp.com/blog/smart-localization-strategy-ikea/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. You can read more about Ikea’s localization strategies on the same. &lt;/p&gt;

&lt;p&gt;All these examples you see are focused on improving the user’s experience. It takes a lot of research and understanding of the user’s region to come up with this user experience. But websites like these makes use you of concept called as website localization to achieve the same.&lt;/p&gt;

&lt;p&gt;So in this blogpost, we will be exploring website localisation, how it differs from translation and its multiple use cases.&lt;/p&gt;

&lt;p&gt;So without any further ado, let us get started!!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Website Localisation?
&lt;/h2&gt;

&lt;p&gt;Website localisation is a method/a way to make sure the website adapts to the user’s location so that the experience is enhanced. &lt;/p&gt;

&lt;p&gt;Adaption of a website based on user’s location can mean a lot of things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making sure the website’s content is aligned correctly i.e. LTR or RTL.&lt;/li&gt;
&lt;li&gt;Making sure the images, audio and videos are appropriate as per the user’s region.&lt;/li&gt;
&lt;li&gt;Making sure the text is translated according to the user’s location.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combining all the ways of adaption, website try to create a personalised experience for the user which make them feel familiar and isn’t hard to navigate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is Website localisation same as text translation ?
&lt;/h2&gt;

&lt;p&gt;We can say that text translation is a part of localisation i.e. localisation is a super set of text translation.&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%2Flh7hrvum2fmqqaizkrd2.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%2Flh7hrvum2fmqqaizkrd2.png" alt="Localization being superset of text translation" width="786" height="770"&gt;&lt;/a&gt;

&lt;/p&gt;

&lt;p&gt;Website localisation includes adapting the website’s content as per the user’s region. But translation is converting the text to the language which is native at the user’s location.&lt;/p&gt;

&lt;p&gt;It is important to note that text translation should also cater to the user’s dialect to provide an optimum experience. We will talk more about this in the coming sections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases of Website Localization
&lt;/h2&gt;

&lt;p&gt;Website localisation is highly useful for businesses who are trying to have a global reach. By global reach, we mean that they want to expand to other countries so that they can increase their business. &lt;/p&gt;

&lt;p&gt;The examples of such business are everywhere from e-commerce, food industries, pharmaceutical to automobile industries. With the help of localisation it helps these businesses to expand further and show their capabilities on how they cater the needs of their customers.&lt;/p&gt;

&lt;p&gt;I feel website localisation is very important for businesses mentioned above because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It tells that the company fosters user empathy.&lt;/li&gt;
&lt;li&gt;It makes sure that user are comfortable and they feel safe while browsing their websites.&lt;/li&gt;
&lt;li&gt;Provides correct interpretation of what the user needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let us look at a couple of ways through which localisation has helped businesses empathise more towards users:&lt;/p&gt;

&lt;h3&gt;
  
  
  Text Translation
&lt;/h3&gt;

&lt;p&gt;Often not people think that website localisation is nothing but text translation. But yeah that being partially true website localisation is much more than that. As we saw above that it is a super set of text translation. &lt;/p&gt;

&lt;p&gt;Text translation is the key aspect of website localisation. People think that, why should we manually translate a website were we already have google translate that will help us to do that on the fly. While that being true in some cases, the translation provided cannot be always correct. &lt;/p&gt;

&lt;p&gt;The translation provided by these app should make sure that they also match the dialect of the user location.&lt;/p&gt;

&lt;p&gt;For example, google translate can make mistakes, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Take a hike" vs. "Haz una caminata":&lt;/strong&gt; In English, "take a hike" is often used as a rude dismissal, while in Spanish, "haz una caminata" simply means "take a walk."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Y'all"&lt;/strong&gt; - A common Southern American English term, it can be challenging to translate accurately, often resulting in awkward or incorrect phrases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Mate"&lt;/strong&gt; - A common Australian and British term for friend, it can be misinterpreted in other cultures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So text translation which involves professional translation services can recognize idioms and find equivalent phrases in the target language to maintain the same tone.&lt;/p&gt;

&lt;p&gt;Text translated by these apps can also contract or expand the text space. This in turn affects the spacing and layout on the page. So it becomes beneficial to have custom translation placed on the website to avoid such scenarios. Here is a quick example of IKEA’s language change section differs in text sizes when language is changed from english to arabic.&lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvomigg375xo7kmqr6g93.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%2Fvomigg375xo7kmqr6g93.png" alt="Text Expansion in English" width="800" height="468"&gt;&lt;/a&gt;Text Expansion in English
  

&lt;/p&gt;

&lt;p&gt;Similar text in the Arabic text is smaller:&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%2Fjoxjaedgoh95ogtrf9cs.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%2Fjoxjaedgoh95ogtrf9cs.png" alt="Text Contraction in Arabic" width="800" height="589"&gt;&lt;/a&gt;Text Contraction in Arabic
  

&lt;/p&gt;

&lt;h2&gt;
  
  
  Content Relevance And Placement
&lt;/h2&gt;

&lt;p&gt;Another key aspect of website localisation is the making sure the content is relevant and placed correctly on the website. &lt;/p&gt;

&lt;h3&gt;
  
  
  Content Relevance
&lt;/h3&gt;

&lt;p&gt;If you have observed food chains such as McDonald’s or KFC, they have different menus for different countries. They make sure that menu are created in such a way that the items available, are as per the local traditions and adhere to the culture neutral zone.&lt;/p&gt;

&lt;p&gt;For example, In US you would find a big mac burger made out beef patty, it’s equivalent in India is Maharaja Mac burger with a chicken patty. &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%2F2eynd4ck7hdz41u07jz7.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%2F2eynd4ck7hdz41u07jz7.png" alt="The Maharaja Mac" width="800" height="410"&gt;&lt;/a&gt;The Maharaja Mac
  

&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%2F1sqx7aj9ojuc84z4fyrs.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%2F1sqx7aj9ojuc84z4fyrs.png" alt="The Big Mac" width="800" height="410"&gt;&lt;/a&gt;The Big Mac
  

&lt;/p&gt;

&lt;h3&gt;
  
  
  Content Placement
&lt;/h3&gt;

&lt;p&gt;Another important factor on websites is the content placement. Let us look at this via examples, &lt;/p&gt;

&lt;p&gt;Websites needs to make sure that their content caters for users from all the regions. A person from a middle eastern region, would generally prefer their text to be placed in right to left format instead of left to right. &lt;/p&gt;

&lt;p&gt;Here is a look at how the IKEA’s website looks like for an arabic region as compared to the India version of the website:&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%2Fsle869qfra00xwdpbbup.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%2Fsle869qfra00xwdpbbup.png" alt="IKEA website of middle east region in Arabic language" width="800" height="383"&gt;&lt;/a&gt;IKEA website of middle east region in Arabic language
  

&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%2Fb72wku3t5bwnmfao6q4y.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%2Fb72wku3t5bwnmfao6q4y.png" alt="IKEA website of Indian region in English language" width="800" height="383"&gt;&lt;/a&gt;IKEA website of Indian region in English language
  

&lt;/p&gt;

&lt;p&gt;As you can see in the above images that text is preferred in right to left format for Arabic region as compared to the India version. Another keen example of content placement in this scenario is the placement of the language change button(highlighted in green) and the tablist(highlighted in blue). If you see, for Arabic region both the button and tablist starts from right which isn’t the case for Indian region of the site.&lt;/p&gt;

&lt;p&gt;These minute details creates a thoughtful user experience for a variety of regions. Thus content placement is one of the important aspects of the website localization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hyperlocalisation
&lt;/h2&gt;

&lt;p&gt;It is a kind of localisation that is very specific to the user’s needs and most of the time it caters to user’s preferences. This helps the websites create a deeper and personalized impact with the user. We can consider hyperlocalisation to be an advanced version of website localisation which focuses much on content relevance.&lt;/p&gt;

&lt;p&gt;A classic example that I found &lt;a href="https://lokalise.com/blog/translation-and-localization-difference/#Spotify" rel="noopener noreferrer"&gt;here&lt;/a&gt; is with Spotify. They shared this ad which targeted the users from Mumbai who can related to being stuck in a heavy traffic:&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%2Fa7gmcgigwo7445jwndlh.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%2Fa7gmcgigwo7445jwndlh.png" alt="Spotify's Audience Targeting to achieve Hyperlocalization" width="800" height="395"&gt;&lt;/a&gt;Spotify's Audience Targeting to achieve Hyperlocalization
  

&lt;/p&gt;

&lt;p&gt;There are a lot of examples on hyperlocalization, some of them we saw in the introduction section of the blog. Hence it is important for products that revolve around user’s bevhavior to have hyper-localization.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can this be achieved?
&lt;/h2&gt;

&lt;p&gt;There are many products out there such as &lt;a href="https://lokalise.com/" rel="noopener noreferrer"&gt;Lokalize&lt;/a&gt;, &lt;a href="https://crowdin.com/" rel="noopener noreferrer"&gt;Crowdin&lt;/a&gt;, &lt;a href="https://www.weglot.com/" rel="noopener noreferrer"&gt;Weglot&lt;/a&gt;, &lt;a href="https://business.adobe.com/products/target/adobe-target.html" rel="noopener noreferrer"&gt;Adobe Target&lt;/a&gt;, etc can be used to achieve these experiences. Diving into the details and the general working of these products is out of scope of this blog post. But do give these products a try.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this blogpost, we learned various aspects of website localization including it’s definition and how it differs from text translation. We also delved into various use cases which achieve website localization and how they create an impactful user experience.&lt;/p&gt;

&lt;p&gt;So that’s all folks!. Hope you like my blog post.&lt;/p&gt;

&lt;p&gt;You can follow me on &lt;a href="https://twitter.com/keurplkar" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar" rel="noopener noreferrer"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/" rel="noopener noreferrer"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>react</category>
      <category>learning</category>
    </item>
    <item>
      <title>Master TypeScript: Let's Do Math In Type System</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Sun, 28 Jul 2024 10:28:10 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/master-typescript-lets-do-math-in-type-system-2j73</link>
      <guid>https://forem.com/keyurparalkar/master-typescript-lets-do-math-in-type-system-2j73</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExMXV6bzUwcThqaWx6Mzhrdm9uZGF3am8wOHE1ZGplNmFxaTVxNXNicSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/UThpUbZef3ulWxgvfn/giphy-downsized.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExMXV6bzUwcThqaWx6Mzhrdm9uZGF3am8wOHE1ZGplNmFxaTVxNXNicSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/UThpUbZef3ulWxgvfn/giphy-downsized.gif" alt="A duck understanding math"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our day to day lives we do Mathematical operations without any hassle and worry. Because we have all the tools we need like, numbers and the operators. Like 5 + 2 = 7, here we know that 5, 2, and 7 are numbers and what we are essentially doing is adding because of the operator &lt;code&gt;+&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, just imagine you don’t know what the numbers mean or their actual interpretation. You also don’t know the meaning of the &lt;code&gt;+&lt;/code&gt; symbol, but you still want to add two numbers. It's like a toddler trying to do this!&lt;/p&gt;

&lt;p&gt;I welcome you to the world of TypeScript where you cannot do all these stuffs. TypeScript does understand numbers but doesn’t have the understanding of what numbers represent and how big they are, what exactly are mathematical operations. &lt;/p&gt;

&lt;p&gt;So in this blogpost, I will be explaining you folks, how to do the exact same thing and try to make it more humane.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.typescriptlang.org/docs/handbook/2/conditional-types.html" rel="noopener noreferrer"&gt;Conditional Types in TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/microsoft/TypeScript/pull/39094" rel="noopener noreferrer"&gt;Variadic Elements and Tuples in TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who is this blog post not for?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcGp2eG84MmVtc3JvOTk2cHl4bHozaGZhazgyenZpdHh3b29jN3o0NCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/n4lK173IddTFe/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcGp2eG84MmVtc3JvOTk2cHl4bHozaGZhazgyenZpdHh3b29jN3o0NCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/n4lK173IddTFe/giphy.gif" alt="A duck understanding math"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me tell you the hard truth upfront: this blog post is one of those rare cases where you might not need it. The purpose of this post is to understand the marvelous concepts used to implement such things in TypeScript.&lt;/p&gt;

&lt;p&gt;I love TypeScript, and for fun, I am trying to dig into this!&lt;/p&gt;

&lt;h2&gt;
  
  
  What are we building?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExN2NiMHNkMGM4OTBxemY2eHQ1aG1wcm51MXhjaWZodGFqNDQybWhqdyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/q0eh4TU8OMXRu/giphy-downsized.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExN2NiMHNkMGM4OTBxemY2eHQ1aG1wcm51MXhjaWZodGFqNDQybWhqdyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/q0eh4TU8OMXRu/giphy-downsized.gif" alt="Lets build together"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In TypeScript you cannot do any arithmetic operation like the above &lt;code&gt;5+2&lt;/code&gt; which is equal to 7. You can represent numbers in typescript like &lt;code&gt;5&lt;/code&gt; or &lt;code&gt;2&lt;/code&gt; but you cannot do anything with them.&lt;/p&gt;

&lt;p&gt;In this blogpost we will be building typescript generic utilities that will help you to implement the arithmetic operations: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Addition&lt;/li&gt;
&lt;li&gt;Subtraction&lt;/li&gt;
&lt;li&gt;Multiplication&lt;/li&gt;
&lt;li&gt;Division&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After going through this blogpost, you will be able to achieve the following in TYPES!!!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;addResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// 7&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;subRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Sub&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 47&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;mulRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Mul&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;10&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 20&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;divRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Div&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  The Basics
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcW5pbHBva2ExazNjNHE1dndicDlibmR4bDE1NXNtc2V5ZW1pajZiaSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/0RAvDxfdksWy39YG4T/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcW5pbHBva2ExazNjNHE1dndicDlibmR4bDE1NXNtc2V5ZW1pajZiaSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/0RAvDxfdksWy39YG4T/giphy.gif" alt="Foundation is the key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every good code that is implemented is based on a good foundation. In this section we will talk about the foundation of implementing the above generic utilities.&lt;/p&gt;

&lt;p&gt;There are two main thing that we need to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recursion&lt;/li&gt;
&lt;li&gt;And Tail Recursion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These concepts are really important and drive the entire thought process about these generic arithmetic utilities in TypeScript.&lt;/p&gt;

&lt;p&gt;So let us start off by understanding recursion.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is Recursion?
&lt;/h3&gt;

&lt;p&gt;Recursion is the way through which you can perform certain action by calling the same action. In terms of real life example, recursion can look like this:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fs64ak4fk0lsrz1r0bjsi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fs64ak4fk0lsrz1r0bjsi.png" alt="Mirror in Mirror"&gt;&lt;/a&gt;Recursion in real life
  

&lt;/p&gt;

&lt;p&gt;If you hold a mirror in front of a mirror then you see an endless mirror within mirrors. &lt;/p&gt;

&lt;p&gt;In the similar way, recursion in programming is a way for a function to achieve the results by calling it self. To explain this further let me give you a classic yet simple example,&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sum1ToN&lt;/span&gt; &lt;span class="o"&gt;=&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="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="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;num&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="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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;sum1ToN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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;This function will return the sum of all the numbers from 1 to N.&lt;/p&gt;

&lt;p&gt;To give you guys a quick look let us see what happens from call stack perspective(I know this is a bit off the route but trust me this will help us understand the later section of the blogpost):&lt;/p&gt;

&lt;p&gt;If you execute &lt;code&gt;sum1ToN(4)&lt;/code&gt;. This is what happens&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;sum1ToN&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="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;sum1ToN&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="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;sum1ToN&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="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;sum1ToN&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="c1"&gt;// &amp;lt;-------&lt;/span&gt;

&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;

&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;

&lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the call stack, numbers are unraveled until &lt;code&gt;num = 0&lt;/code&gt;. Once all numbers are spread out, reverse addition occurs, consuming more of the call stack. For example, when &lt;code&gt;num&lt;/code&gt; was 4, it took 8 stacks to finish. Imagine if &lt;code&gt;num&lt;/code&gt; is 100.&lt;/p&gt;

&lt;p&gt;This unpacking method in recursion is inefficient because the last statement in &lt;code&gt;sum1ToN&lt;/code&gt; performs two operations: unpacking the number and calling the next number in recursion. The program must remember the previous steps.&lt;/p&gt;

&lt;p&gt;But why study this? What does recursion have to do with efficiency?&lt;/p&gt;

&lt;p&gt;Find out in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limitations in TypeScript
&lt;/h3&gt;

&lt;p&gt;All the arithmetic generic utilities that we are going to build involves heavy recursion to achieve the results. Next, the typescript has limitation on its call stack size. Following are the TypeScript limits of the call stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If it is a normal statement in TS then recursion limit is 100.&lt;/li&gt;
&lt;li&gt;If it is inside a conditional statement then limit is below 1000.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hence, if we go with the above normal recursion methods to implement our utilities then it would fill up these limits easily even with small numbers like 200 or so if the utilities are not implemented correctly.&lt;/p&gt;

&lt;p&gt;The aim of our utilities would be that they should take inputs less 1000.&lt;/p&gt;

&lt;p&gt;You can read more about these TS limits in this PR: &lt;a href="https://github.com/microsoft/TypeScript/pull/45711" rel="noopener noreferrer"&gt;https://github.com/microsoft/TypeScript/pull/45711&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Tail Recursion?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExNW9rdnpua3lwbzR2dTFuaG8yaGlrdngyZTN1N2RteHpvdnh0dWhsMCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/hVazFLob1BnLpuWoXx/giphy-downsized.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExNW9rdnpua3lwbzR2dTFuaG8yaGlrdngyZTN1N2RteHpvdnh0dWhsMCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/hVazFLob1BnLpuWoXx/giphy-downsized.gif" alt="Now we are getting started"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a way out to this normal recursion technique where you can do these calculations efficiently by reducing the call stack sizes. This method is called as tail recursion. I am not going to go in-depth about tail recursion in this post but I will help you understand how it affects the call stack.&lt;/p&gt;

&lt;p&gt;So tail recursion is a technique in which the last statement of the recursive function just calls the function it self and doesn’t do any further calculations combined with it. &lt;/p&gt;

&lt;p&gt;For example, in the above &lt;code&gt;sum1ToN&lt;/code&gt; function the last statement &lt;code&gt;num + sum1ToN(num -1)&lt;/code&gt; should not be present in the tail recursion method according to its definition.&lt;/p&gt;

&lt;p&gt;If we cannot do combined operation as the last call in our recursive function then how are we going to achieve results? Its simple, just make use of accumulator to remember the addition of the already visited numbers. Below is the quick look of tail recursion version of &lt;code&gt;sum1ToN&lt;/code&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;sum1ToN&lt;/span&gt; &lt;span class="o"&gt;=&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="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;acc&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;=&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;=&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;num&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="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sum1ToN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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;acc&lt;/span&gt; &lt;span class="o"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here, we introduce the second argument &lt;code&gt;acc&lt;/code&gt; to the function with a default value of &lt;code&gt;0&lt;/code&gt;. This way, the program doesn’t need to remember previous calls. In our case, while unpacking the numbers in the call stack, we are also performing the calculations in the accumulator as shown below:&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;sum1ToN&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="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;sum1ToN&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;0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;sum1ToN&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;0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&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="nf"&gt;sum1ToN&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="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&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="c1"&gt;// finally the acc is returned&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;See how the call stack got reduced!!! we don’t need to go through all the next steps of addition because we are doing addition while we are doing the unpacking of the numbers. Isn’t this great 🙂&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;NOTE&lt;/strong&gt; Even though this technique is efficient still at some point in our utilities we hit the above mentioned limits.&lt;/p&gt;

&lt;p&gt;You can find out more about tail recursion in the below detailed and fantastic videos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=-PX0BV9hGZY" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=-PX0BV9hGZY&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=_JtPhF8MshA" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=_JtPhF8MshA&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Let us dive into the implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExZHJ1bG84cXZmb3U5aTdxemhmYmxxb212dGY4aGp1N2lvMDdiMWJwZSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/SiKqNZqksVYWmQEMjd/giphy-downsized.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExZHJ1bG84cXZmb3U5aTdxemhmYmxxb212dGY4aGp1N2lvMDdiMWJwZSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/SiKqNZqksVYWmQEMjd/giphy-downsized.gif" alt="Let us dive into the implementation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this section we will be implementing the following arithmetic utilities which look like below:&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;Add&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&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;B&lt;/span&gt; &lt;span class="kd"&gt;extends&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="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;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&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;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;B&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&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;Sub&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&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;B&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Num1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&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;Num2&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;B&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;Num2&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;Num1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// A &amp;lt; B; res = -ve&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;R&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&lt;/span&gt;&lt;span class="dl"&gt;"&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;Num1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;Num2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// A &amp;gt; B; res = +ve&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&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="mi"&gt;0&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;Mul&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&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;B&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Counter&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;Acc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;Num1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&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;B&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&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;Mul&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Inc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;Counter&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;Acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;Num1&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;type&lt;/span&gt; &lt;span class="nx"&gt;Div&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;N&lt;/span&gt; &lt;span class="kd"&gt;extends&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;D&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Acc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;ReducedN&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;D&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;infer&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="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&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="mi"&gt;0&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;N&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;length&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;Div&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReducedN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;Acc&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="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;I know these generic might look way difficult but trust me they are easy to understand. I will break down each and every part of these generic utilities so that you guys can grasp the concept behind it.&lt;/p&gt;

&lt;p&gt;So without further ado, let us start by implementing our first utility &lt;code&gt;Add&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add
&lt;/h2&gt;

&lt;p&gt;In terms of arithmetic this is a no brainer, &lt;code&gt;Add&lt;/code&gt; utility will just add two numbers. There are couple of things that you need to understand before we start off with the implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We cannot do addition or any arithmetic operation of that sort. So to by-pass this we convert each input number into a tuple of numbers. For example, a number &lt;code&gt;4&lt;/code&gt; will be represented as a tuple of four 0s i.e. &lt;code&gt;[0, 0, 0, 0]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We will need an utility to generate tuples out of the input numbers&lt;/li&gt;
&lt;li&gt;Numbers greater than 1000 cannot be used because we might reach the TS stack limit discussed above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So here is how our &lt;code&gt;Add&lt;/code&gt; utility will look like:&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;Add&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&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;B&lt;/span&gt; &lt;span class="kd"&gt;extends&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="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;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&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;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;B&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&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;Before we jump into the implementation, let us understand what the &lt;code&gt;GetRange&lt;/code&gt; utility is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Generates a tuple of 0s for the specified number
 */&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;N&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Acc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;N&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Acc&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;Acc&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;This utility will generate a tuple filled with 0s equal to number passed as input. So indeed it will do something like below:&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// res = [0, 0, 0, 0]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;

&lt;a href="https://media.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%2F0gb2vjyfo02saquq8fyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F0gb2vjyfo02saquq8fyh.png" alt="GetRange flowchart"&gt;&lt;/a&gt;GetRange flowchart
  

&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;GetRange&lt;/code&gt; utility works in the following manner:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It takes input number for which the tuple range needs to be created which is &lt;code&gt;N&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It also makes use of accumulator &lt;code&gt;Acc&lt;/code&gt; which stores the actual range in each step of recursion.&lt;/li&gt;
&lt;li&gt;Its a simple recursion where we check if the length of &lt;code&gt;Acc&lt;/code&gt; equals to the number &lt;code&gt;N&lt;/code&gt; then we stop the recursion and return the &lt;code&gt;Acc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If not, we again call the &lt;code&gt;GetRange&amp;lt;N, [0, ...Acc]&amp;gt;&lt;/code&gt; which passes updated &lt;code&gt;Acc&lt;/code&gt; to the &lt;code&gt;GetRange&lt;/code&gt; with an addition of &lt;code&gt;0&lt;/code&gt; and the previous values of &lt;code&gt;Acc&lt;/code&gt; by destructing it an array like this &lt;code&gt;[0, ...Acc]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Taking a closer look at this utility, we can see that we are using the Tail recursion mechanism, since the last statement in the recursion is only the recursive call to the function and no other operation. And also we are making use of accumulator &lt;code&gt;Acc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let us re-visit our &lt;code&gt;Add&lt;/code&gt; utility. In this utility we simple destructure the tuples from &lt;code&gt;GetRange&amp;lt;A&amp;gt;&lt;/code&gt; and &lt;code&gt;GetRange&amp;lt;B&amp;gt;&lt;/code&gt; inside an array. Finally we return the length of this array:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fevpdkj6f16ogvbp8gq5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fevpdkj6f16ogvbp8gq5w.png" alt="Add flowchart"&gt;&lt;/a&gt;Add flowchart
  

&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;Add&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&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;B&lt;/span&gt; &lt;span class="kd"&gt;extends&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="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;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&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;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;B&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&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;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;sum1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Subtract
&lt;/h2&gt;

&lt;p&gt;Here is how the subtraction utility will look like in TypeScript:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Substracts two numbers
 */&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Sub&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&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;B&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Num1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&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;Num2&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;B&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;Num2&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;Num1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// A &amp;lt; B; res = -ve&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;R&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&lt;/span&gt;&lt;span class="dl"&gt;"&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;Num1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;Num2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// A &amp;gt; B; res = +ve&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&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="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;The output of this utility is either string when the output is a negative or a number when output is positive.&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;subRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Sub&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// subRes = 47&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;subRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Sub&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// subRes = "-47"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To understand this utility take a look at this flowchart:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fdqsuqrst91ujo6iio5he.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fdqsuqrst91ujo6iio5he.png" alt="Sub flowchart"&gt;&lt;/a&gt;Sub flowchart
  

&lt;/p&gt;

&lt;p&gt;Let us go through it step by step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Sub&lt;/code&gt; take 2 mandatory inputs which are &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;. It also has 2 default parameters &lt;code&gt;Num1&lt;/code&gt; and &lt;code&gt;Num2&lt;/code&gt; with the default value of &lt;code&gt;GetRange&lt;/code&gt;'s of &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Throughout the utility we make we make use of &lt;code&gt;Num1&lt;/code&gt; and &lt;code&gt;Num2&lt;/code&gt; because it makes easier for comparison as we will see in the next steps.&lt;/li&gt;
&lt;li&gt;It’s easier to compare the array’s with the help of variadic tuple feature of TypeScript. We first compare that if &lt;code&gt;B&lt;/code&gt; is greater than &lt;code&gt;A&lt;/code&gt; , if it is then our output would be negative i.e. &lt;code&gt;A-B = -res&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We do that by comparing &lt;code&gt;Num2&lt;/code&gt; tuple with an destructured tuple of &lt;code&gt;Num1&lt;/code&gt; and a variadic element &lt;code&gt;R&lt;/code&gt;. Here &lt;code&gt;R&lt;/code&gt; represents the left over 0s from &lt;code&gt;Num2&lt;/code&gt; which in our case is the result.&lt;/li&gt;
&lt;li&gt;If this is the case then we return a string &lt;code&gt;-R&lt;/code&gt;'s length.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can imagine this calculation in this way:&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Sub&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Num1&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;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;Num2&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;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;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// Inside Sub this is what happens when A &amp;lt; B:&lt;/span&gt;

&lt;span class="nx"&gt;Sub&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Num1&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;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;Num2&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;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;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="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;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&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;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// Here R's value becomes [0]&lt;/span&gt;

&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`-[0]['length']`&lt;/span&gt; &lt;span class="c1"&gt;// -1&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Similarly if &lt;code&gt;A&lt;/code&gt; is greater than &lt;code&gt;B&lt;/code&gt; then the output will be positive and the result of the residue is stored in &lt;code&gt;T&lt;/code&gt; in this case which is a Tuple whose length we return as the output.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Multiplication
&lt;/h2&gt;

&lt;p&gt;The Multiplication utility is a bit different than the &lt;code&gt;Add&lt;/code&gt; and &lt;code&gt;Sub&lt;/code&gt;. Here is how it looks like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Multiplies two numbers
 */&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Mul&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&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;B&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Counter&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;Acc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;Num1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&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;B&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&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;Mul&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Inc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;Counter&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;Acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;Num1&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;This utility works on the following principle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consider an example of &lt;code&gt;Mul&amp;lt;2,3&amp;gt;&lt;/code&gt;, to generate an output of &lt;code&gt;6&lt;/code&gt; we should add number &lt;code&gt;2&lt;/code&gt; three times to get the value as &lt;code&gt;6&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;So in this utility the first number, is the input that will be repeatedly added with itself &lt;code&gt;B&lt;/code&gt; number of times which is our second input to &lt;code&gt;Mul&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what happens inside the utility:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fzxh78brohhz0jk04nx3a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fzxh78brohhz0jk04nx3a.png" alt="Mul Flowchart"&gt;&lt;/a&gt;Mul utility flowchart
  

&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The utility takes 2 mandatory number based inputs &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;. It takes 3 optional parameters &lt;code&gt;Counter&lt;/code&gt; &lt;code&gt;Acc&lt;/code&gt; and &lt;code&gt;Num1&lt;/code&gt; with it’s respective default values mentioned in the utility.&lt;/li&gt;
&lt;li&gt;Since we are add &lt;code&gt;A&lt;/code&gt; to itself &lt;code&gt;B&lt;/code&gt; number of times therefore we need to check if we have actually done that or not. To do that we compare &lt;code&gt;B&lt;/code&gt; with the &lt;code&gt;Counter&lt;/code&gt;, if it matches then we return the length of the &lt;code&gt;Acc&lt;/code&gt; i.e. Accumulator which keeps track of this addition.&lt;/li&gt;
&lt;li&gt;Or else we again call &lt;code&gt;Mul&lt;/code&gt; with &lt;code&gt;A&lt;/code&gt; &lt;code&gt;B&lt;/code&gt;, with an incremented &lt;code&gt;Counter&lt;/code&gt; with the help of &lt;code&gt;Inc&lt;/code&gt; utility and finally we pass a tuple with desctructure value of &lt;code&gt;Acc&lt;/code&gt; and &lt;code&gt;Num1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The last parameter to &lt;code&gt;Mul&lt;/code&gt; in the recursive call is important because it stores the actual results.&lt;/li&gt;
&lt;li&gt;The Incremented counter value is also important because it helps to stop the recursion.&lt;/li&gt;
&lt;li&gt;Here is how the &lt;code&gt;Inc&lt;/code&gt; utility looks like, it is pretty straight forward hence not going to explain:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Utility to increment the number
 */&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Inc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt; &lt;span class="kd"&gt;extends&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="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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&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;h2&gt;
  
  
  Division
&lt;/h2&gt;

&lt;p&gt;Similar to multiplication utility, in Division we try to reduce the numerator by denominator till the numerator becomes 0. While this is happening we maintain the count of no. of times numerator was reduced. &lt;/p&gt;

&lt;p&gt;For this utility we are apply the following constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The numerator should be greater than the denominator.&lt;/li&gt;
&lt;li&gt;Numerator should be perfectly divisble by the denominator.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are going to keep these constraints to our &lt;code&gt;Div&lt;/code&gt; utility because implementing use cases such as not divisble numbers, floating point numbers, negative numbers, recurring decimal digits etc makes the utility too complicated and is out of scope of this blog post.&lt;/p&gt;

&lt;p&gt;Here is how the utility will look like:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Divides two numbers
 */&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Div&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;N&lt;/span&gt; &lt;span class="kd"&gt;extends&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;D&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Acc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;ReducedN&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;GetRange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;D&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;infer&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="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;length&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="mi"&gt;0&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;N&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;length&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;Div&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReducedN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;Acc&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="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;Inside the utility following things happen:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fziauyjgtp71uuv3513dh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fziauyjgtp71uuv3513dh.png" alt="Div flowchart"&gt;&lt;/a&gt;Div utility flowchart
  

&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are 2 mandatory inputs &lt;code&gt;N&lt;/code&gt; and &lt;code&gt;D&lt;/code&gt; which stands for Numerator and Denominator.&lt;/li&gt;
&lt;li&gt;Next, we have 2 optional inputs &lt;code&gt;Acc&lt;/code&gt; and &lt;code&gt;ReducedN&lt;/code&gt; with their respective default values.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Acc&lt;/code&gt; is the accumulator tuple that we use to keep a count of number of times we subtracted &lt;code&gt;D&lt;/code&gt; from &lt;code&gt;N&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ReducedN&lt;/code&gt; has a default value &lt;code&gt;GetRange&amp;lt;N&amp;gt; extends [...GetRange&amp;lt;D&amp;gt;, ...infer T] ? T["length"] : 0&lt;/code&gt; which compares the &lt;code&gt;N&lt;/code&gt; tuple with a tuple of &lt;code&gt;D&lt;/code&gt; and a varidiac element &lt;code&gt;T&lt;/code&gt;. This value is nothing but subtraction of &lt;code&gt;D&lt;/code&gt; from &lt;code&gt;N&lt;/code&gt;. You can refer to the &lt;code&gt;Sub&lt;/code&gt; utility for this to understand the logic.&lt;/li&gt;
&lt;li&gt;Next, inside the actual utility we check that if &lt;code&gt;N&lt;/code&gt; has been exhausted completely i.e. &lt;code&gt;N&lt;/code&gt; is equal to 0. If it is then we return the length of the &lt;code&gt;Acc&lt;/code&gt; or else we again call the &lt;code&gt;Div&lt;/code&gt; with &lt;code&gt;ReducedN&lt;/code&gt; as &lt;code&gt;N&lt;/code&gt;, with same &lt;code&gt;D&lt;/code&gt; as the denominator, and with an incremented &lt;code&gt;Acc&lt;/code&gt; by appending &lt;code&gt;0&lt;/code&gt; to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcWpqZ2g2ZmNwOWNjamZpMWd6MnV3ZzUxcHJrZnc4cXV3enFtcWp1NSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/5iWX6XFTndU0YP0Yut/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcWpqZ2g2ZmNwOWNjamZpMWd6MnV3ZzUxcHJrZnc4cXV3enFtcWp1NSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/5iWX6XFTndU0YP0Yut/giphy.gif" alt="Matrix-red pill or blue pill"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The purpose of these utilities is to understand different concepts and the power of typescript. Below are some of the uses cases that are purposely not implemented since it would overcomplicate stuff and would be out of scope of this blog post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For &lt;code&gt;Add&lt;/code&gt; utility, we didn’t consider addition of negative numbers or combination of negative and positive numbers. This also leads to connectivity between &lt;code&gt;Sub&lt;/code&gt; utility as well. This limitation also applies to &lt;code&gt;Mul&lt;/code&gt; and &lt;code&gt;Div&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For all the utilities, operations related floating point numbers is not considered.&lt;/li&gt;
&lt;li&gt;Due to call stack limitation of TS we cannot do operations on numbers more than 999.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExdXM1dW1lZDNvb2E2NGdobnRqMnkzeXYxenozeGh3dDZnc3FxY2ZseSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/xUPOqo6E1XvWXwlCyQ/giphy-downsized.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExdXM1dW1lZDNvb2E2NGdobnRqMnkzeXYxenozeGh3dDZnc3FxY2ZseSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/xUPOqo6E1XvWXwlCyQ/giphy-downsized.gif" alt="That's all folks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I know this blogpost isn’t going to be that fruitful in real life use cases but take a look at what are the things we learned from it today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We understood recursion and Tail recursion&lt;/li&gt;
&lt;li&gt;How does tail recursion helps in optimizing the code by reducing the call stack consumption.&lt;/li&gt;
&lt;li&gt;We saw how Typescript interprets numbers and also saw that we cannot do arithematic operations&lt;/li&gt;
&lt;li&gt;We learned Typescript’s limitation of its call stack size.&lt;/li&gt;
&lt;li&gt;We learned how we can interpret numbers in the form of tuple like &lt;code&gt;GetRange&lt;/code&gt; and &lt;code&gt;Inc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lastly, we saw how we can leverage the above technique to create &lt;code&gt;Add&lt;/code&gt; &lt;code&gt;Sub&lt;/code&gt; &lt;code&gt;Mul&lt;/code&gt; and &lt;code&gt;Div&lt;/code&gt; utilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So that’s all folks!. Hope you like my blog post.&lt;/p&gt;

&lt;p&gt;You can follow me on &lt;a href="https://twitter.com/keurplkar" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar" rel="noopener noreferrer"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/" rel="noopener noreferrer"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Mastering TypeScript: Implementing Push, Pop, Shift, and Unshift in Tuples</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Tue, 18 Jun 2024 02:05:50 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/mastering-typescript-implementing-push-pop-shift-and-unshift-in-tuples-5833</link>
      <guid>https://forem.com/keyurparalkar/mastering-typescript-implementing-push-pop-shift-and-unshift-in-tuples-5833</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExN2ludHpiMHJoZ3h6dTB0bXl0dHFqb2hsaW53aDY4dzc1dGFoZGFpMyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/l3fZLMbuCOqJ82gec/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExN2ludHpiMHJoZ3h6dTB0bXl0dHFqb2hsaW53aDY4dzc1dGFoZGFpMyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/l3fZLMbuCOqJ82gec/giphy.gif" alt="A wild thought image" width="480" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, here's a wild thought! What if I told you that we can use JS array functions like &lt;code&gt;pop&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;shift&lt;/code&gt;, &lt;code&gt;unshift&lt;/code&gt; with Typescript tuple type? You might be like, why…why would we even need that? Isn't TS already hard enough? Who on earth would want to make it even more complex?&lt;/p&gt;

&lt;p&gt;Look, I did warn you that this is a bit out there. I've kinda become a Typescript fanatic recently and I love digging into some bizarre TS stuff. Plus, it's not just for kicks. It also helps us understand a few crucial TS concepts that can come in handy when crafting your own utilities.&lt;/p&gt;

&lt;p&gt;So let me grab your attention and share with you what we are gonna be doing. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 NOTE: This blog post is totally inspired by Typescript challenges here: &lt;a href="https://github.com/type-challenges/type-challenges?tab=readme-ov-file"&gt;https://github.com/type-challenges/type-challenges?tab=readme-ov-file&lt;/a&gt; The utilities mentioned in this blog were part of these challenges.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What are we gonna do
&lt;/h2&gt;

&lt;p&gt;Its simple we are building typescript utility generics that does same operations as functions of an Array like push pop etc.&lt;/p&gt;

&lt;p&gt;Here are some examples,&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Pop&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;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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;H&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="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;H&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;Shift&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;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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&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="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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Push&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;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="kd"&gt;extends&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="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="nx"&gt;I&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;Unshift&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;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="kd"&gt;extends&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="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;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;popRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Pop&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="mi"&gt;2&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;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;shiftRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Shift&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="mi"&gt;2&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;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;pushRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Push&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="mi"&gt;2&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;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;unshiftRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Unshift&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="mi"&gt;2&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="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExanU0eHM3MmZhM3hqc3h0Nm9kYmN2NmxhY3psb3VjZWY0aWoyYTV5dCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/Yy6GhtIk8l76u8nlIF/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExanU0eHM3MmZhM3hqc3h0Nm9kYmN2NmxhY3psb3VjZWY0aWoyYTV5dCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/Yy6GhtIk8l76u8nlIF/giphy.gif" alt="Let us get started image" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we dive into the implementation of these utilities we first need to understand couple of basic things in TypeScript:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Tuple Types
&lt;/h3&gt;

&lt;p&gt;A tuple type is similar to an &lt;code&gt;Array&lt;/code&gt; type which has known types at the specified index position. A typical example of tuple would like below:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TupleType&lt;/span&gt; &lt;span class="o"&gt;=&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;TupleType&lt;/code&gt; is a tuple type with &lt;code&gt;number&lt;/code&gt; type being at position &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;boolean&lt;/code&gt; type at position &lt;code&gt;1&lt;/code&gt;. Analogous to Javascript arrays, if you try to index tuple type out of its bounds we will get an error&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TupleType&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="c1"&gt;// &amp;lt;------ Tuple type 'TupleType' of length '2' has no element at index '2'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more information on typescript tuple type read its documentation here: &lt;a href="https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types"&gt;TS Tuple Types&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Variadic Tuples
&lt;/h3&gt;

&lt;p&gt;Variadic tuples were introduced in Typescript via this &lt;a href="https://github.com/microsoft/TypeScript/pull/39094"&gt;PR&lt;/a&gt;. According to the PR, variadic tuples are:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The ability for tuple types to have spreads of generic types that can be replaced with actual elements through type instantiation&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some examples of variadic tuples are as follows:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;WrapWithStringAndBool&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="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;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="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="nx"&gt;T&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;type&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;WrapWithStringAndBool&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;2&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="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- [string, 1, 2, 3, 4, boolean]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you checkout the above example, we have &lt;code&gt;WrapWithStringAndBool&lt;/code&gt; generic that accepts an array of unknowns and returns a tuple with &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;boolean&lt;/code&gt; tupes at the first and the last position in the tuple.&lt;/p&gt;

&lt;p&gt;Here the &lt;code&gt;...T&lt;/code&gt; is the variadic element which acts as a placeholder for values from the input &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Variadic tuples has a lot to offer and is a great piece of feature. I would like recommend to go through its rules and examples mentioned in this &lt;a href="https://github.com/microsoft/TypeScript/pull/39094"&gt;PR&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Conditional Types
&lt;/h3&gt;

&lt;p&gt;Every developer knows the &lt;code&gt;if&lt;/code&gt; &lt;code&gt;else&lt;/code&gt; block that helps you to write conditional code. In the similar way, Typescript conditional types take the following format: &lt;code&gt;condition ? trueBranch : falseBranch&lt;/code&gt;. This is very much similar to the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_operator"&gt;ternary operator in JS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a type to become conditional, the &lt;code&gt;condition&lt;/code&gt; part should consist of &lt;code&gt;extends&lt;/code&gt; keyword:&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="nx"&gt;Type&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;OtherType&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;trueBranch&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;falseBranch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Were &lt;code&gt;Type&lt;/code&gt; if matches with &lt;code&gt;OtherType&lt;/code&gt; then &lt;code&gt;trueBranch&lt;/code&gt; is executed or else the &lt;code&gt;falseBranch&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Conditional Types can also be used to narrow the types to provide specific types. Consider the following example from &lt;a href="https://www.typescriptlang.org/cheatsheets/"&gt;Typescript cheatsheet&lt;/a&gt;:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Bird&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;legs&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;legs&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Ant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;legs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&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;Wolf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;legs&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;HasFourLegs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Animal&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;Animal&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;legs&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="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Animal&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Animals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Bird&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Ant&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Wolf&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;FourLegs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;HasFourLegs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Animals&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;--- Dog | Wolf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have 4 types &lt;code&gt;Bird&lt;/code&gt; &lt;code&gt;Dog&lt;/code&gt; &lt;code&gt;Ant&lt;/code&gt; and &lt;code&gt;Wolf&lt;/code&gt; with their respective legs property. Next, we have built &lt;code&gt;HasFourLegs&lt;/code&gt;. It does the following thing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It compares &lt;code&gt;Animal&lt;/code&gt; object with &lt;code&gt;{ legs: 4 }&lt;/code&gt; object with the help of &lt;code&gt;extends&lt;/code&gt; keyword.&lt;/li&gt;
&lt;li&gt;If they are equal, &lt;code&gt;Animal&lt;/code&gt; is returned or else nothing is returned.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the last line we make use of &lt;code&gt;HasFourLegs&lt;/code&gt; by passing it the &lt;code&gt;Animals&lt;/code&gt; union type. A thing to note here is that, when an Union type is provided to the left side of the &lt;code&gt;extends&lt;/code&gt; keyword then all the values of Union are distributed such that each value is tested against the object &lt;code&gt;{ legs: 4 }&lt;/code&gt;. You can read more about the distributive nature of unions over &lt;a href="https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Inferring Within Conditional Types
&lt;/h3&gt;

&lt;p&gt;Conditional types can also be used to infer types when we do comparison with the help of &lt;code&gt;infer&lt;/code&gt; keyword. For example, consider the TS utility &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype"&gt;ReturnType&lt;/a&gt;. This utility returns the return type of the function that is being passed to it. Internally it works in the following ways:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetReturnType&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="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&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;T&lt;/span&gt; &lt;span class="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;R&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="c1"&gt;// &amp;lt;--- number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;trueBranch&lt;/code&gt; of the above example if you closely observe that we make use of &lt;code&gt;infer R&lt;/code&gt;. Here we tell TS like while comparing if &lt;code&gt;T&lt;/code&gt; matches the format to the right of &lt;code&gt;extends&lt;/code&gt; then place the return type of function in &lt;code&gt;R&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When we pass &lt;code&gt;() =&amp;gt; number&lt;/code&gt; to the &lt;code&gt;GetReturnType&lt;/code&gt; a number is returned since it matches the format to the right of &lt;code&gt;extends&lt;/code&gt; keyword in the generic.&lt;/p&gt;

&lt;p&gt;Now that we are clear with our basics, let us start with writing our first utility. &lt;code&gt;Pop&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pop
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExZmg1YTlhYWN4eTdua2x5OXdibmQ4OTRyMDc1YXYzbDd0bzZmN2hhbSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/vN2VlOnSeLd6UJsdRx/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExZmg1YTlhYWN4eTdua2x5OXdibmQ4OTRyMDc1YXYzbDd0bzZmN2hhbSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/vN2VlOnSeLd6UJsdRx/giphy.gif" alt="Pop in TS image" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Javascript a &lt;code&gt;pop&lt;/code&gt; function would remove the last element of an array. To build this in Typescript, we do the following:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Pop&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;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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;H&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="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;H&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 me example what is happening here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We tell TS that &lt;code&gt;Pop&lt;/code&gt; is going to be our generic with parameter &lt;code&gt;T&lt;/code&gt; which can be an array of &lt;code&gt;unknown&lt;/code&gt;s.&lt;/li&gt;
&lt;li&gt;Next, with the help of this: &lt;code&gt;T extends [...infer H, unknown]&lt;/code&gt; we tell TS that the first N-1 elements of the tuple/array T should be inferred with H and the Nth i.e. the last element should be inferred as unknown.&lt;/li&gt;
&lt;li&gt;If the Tuple T matches this pattern then &lt;code&gt;H&lt;/code&gt; is returned or else we return an empty array.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Shift
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExaDExcGF6cndpYm5zczFzeXI2OHJqM3N2bzAxdWVzZ29obTEwdmJ4eCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/xTiTnu8nhFODl7Fvdm/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExaDExcGF6cndpYm5zczFzeXI2OHJqM3N2bzAxdWVzZ29obTEwdmJ4eCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/xTiTnu8nhFODl7Fvdm/giphy.gif" alt="Shift in TS image" width="480" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Javascript array’s has another built-in function that helps you to remove its first element. This is an in-place operation that affects the original array. The returned value by this function is an array’s first element. Here is a quick look of this function:&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&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="mi"&gt;2&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="mi"&gt;4&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;firstElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&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;span class="nx"&gt;firstElement&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;----- 1&lt;/span&gt;
&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;----- [2, 3, 4]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to &lt;code&gt;shift&lt;/code&gt; function, we can create a generic utility in Typescript that removes the first element from a tuple type. Here is how it’s the utility will look like:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Shift&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;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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;R&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 &lt;code&gt;Shift&lt;/code&gt; utility here expects it’s input to be an tuple. In this case, since we don’t exactly know the types inside the tuple hence we extend input &lt;code&gt;T&lt;/code&gt; as &lt;code&gt;unkown[]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To the right hand side, we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We are making using of conditional types, were we check if &lt;code&gt;T&lt;/code&gt; matches the following pattern &lt;code&gt;[unknown, ...infer R]&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;We can also identify the things that we learned in the getting started section.&lt;/li&gt;
&lt;li&gt;We make use of &lt;code&gt;extends&lt;/code&gt; keyword to create a conditional types.&lt;/li&gt;
&lt;li&gt;We also make use of variadic tuple types, where in the right side tuple of &lt;code&gt;extends&lt;/code&gt; we have a inferential variadic element &lt;code&gt;R&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If the condition is met we return &lt;code&gt;R&lt;/code&gt; which is the remaining element of the tuple.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Push &amp;amp; Unshift
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExdGx6ZGJ2eTcwcmk0aDl4ZnZnNTByeDAwcjlqN3pobXU2OXZrd2xseiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/VfNFqPmYorydG/giphy-downsized.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExdGx6ZGJ2eTcwcmk0aDl4ZnZnNTByeDAwcjlqN3pobXU2OXZrd2xseiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/VfNFqPmYorydG/giphy-downsized.gif" alt="Shift in TS image" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similar to Javascript’s push built-in function that appends a new element to the array, we can also create a similar utility:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Push&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;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="kd"&gt;extends&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="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="nx"&gt;I&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 one of the simplest utility from all. The key aspect of this Utility is that, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We make use of destructing of tuple concept with &lt;code&gt;...T&lt;/code&gt;  inside a new tuple.&lt;/li&gt;
&lt;li&gt;To this tuple at the end we add &lt;code&gt;I&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Together this utility would return a new tuple type that combines the elements from &lt;code&gt;T&lt;/code&gt; and adds &lt;code&gt;I&lt;/code&gt; at the end.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the result for the same:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Push&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;2&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="mi"&gt;4&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="c1"&gt;// &amp;lt;----- [1, 2, 3, 4]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to this we have &lt;code&gt;Unshift&lt;/code&gt; as well:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Unshift&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;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="kd"&gt;extends&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="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;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this blog post, we covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tuple Types&lt;/li&gt;
&lt;li&gt;Conditional Types&lt;/li&gt;
&lt;li&gt;Variadic Tuple Types&lt;/li&gt;
&lt;li&gt;Conditionally Inferred Types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lastly, we explored the &lt;code&gt;Push&lt;/code&gt;, &lt;code&gt;Pop&lt;/code&gt;, &lt;code&gt;Shift&lt;/code&gt;, and &lt;code&gt;Unshift&lt;/code&gt; generic utilities in TypeScript, which are analogous to their JavaScript counterparts.&lt;/p&gt;

&lt;p&gt;Thanks a lot for reading my blogpost.&lt;/p&gt;

&lt;p&gt;You can follow me on &lt;a href="https://twitter.com/keurplkar"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Mastering Mapped Types in TypeScript and it's Practical Applications</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Tue, 04 Jun 2024 07:28:52 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/leveraging-mapped-types-in-typescript-practical-applications-1i0h</link>
      <guid>https://forem.com/keyurparalkar/leveraging-mapped-types-in-typescript-practical-applications-1i0h</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When I was new to typescript, I used to write basic interfaces and object types. I didn’t you use to pay much attention towards the reason of these types and nor use to think it from scabality perspective. &lt;/p&gt;

&lt;p&gt;I later on decided to level up myself in the TS game. So I started with the &lt;a href="https://github.com/type-challenges/type-challenges?tab=readme-ov-file"&gt;typescript challenges&lt;/a&gt; where I began with easy problems then went on to the complex ones. The challenges are well structured so that you can learn the basics. But what helped me the most was to analyze the solution of other folks on &lt;a href="https://github.com/type-challenges/type-challenges/issues"&gt;Github Issues&lt;/a&gt; and &lt;a href="https://www.youtube.com/playlist?list=PLOlZuxYbPik180vcJfsAM6xHYLVxrEgHC"&gt;Michgan Typescript’s youtube channel&lt;/a&gt;. This increased my understand of Typescript by 10x. &lt;/p&gt;

&lt;p&gt;These challenges has inspired me to write code that is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scalable&lt;/li&gt;
&lt;li&gt;Structured&lt;/li&gt;
&lt;li&gt;Typesafe&lt;/li&gt;
&lt;li&gt;Less error prone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I started to understand Typescript in a deeper way. All these challenges has inspired me to write this blog post about mapped types in Typescript. So in this blogpost, I am going to talk about Mapped typescript type in brief and explains its real-life applications in detail.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;NOTE:&lt;/strong&gt; These application of mapped types can be found in the challenges of typescript shared above.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Mapped Types in Typescript?
&lt;/h2&gt;

&lt;p&gt;Mapped types in TS is nothing but a way through which you can traverse the properties of the typescript object type and modify them as you require.&lt;/p&gt;

&lt;p&gt;To quote the &lt;a href="https://www.typescriptlang.org/cheatsheets/"&gt;TS cheatsheet&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Mapped Types acts like a map statement for the type system, allowing an input to change the structure of the new type&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Consider the following the following type:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&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="s1"&gt;Car&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;noOfWheels&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="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&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;Now imagine that you need to generate a new type from the &lt;code&gt;Vehicle&lt;/code&gt; type such that all the parameters are optional. Here mapped types can be used to effectively get this requirement right like below:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Car&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;P&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;Vehicle&lt;/span&gt;&lt;span class="p"&gt;]?:&lt;/span&gt; &lt;span class="nx"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&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 would generate all the properties that are optional. This is a simple use case but mapped types can do a lot more exciting stuffs. You can read how you can modify the properties in the mapped typed in this section of the TS docs: &lt;a href="https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers"&gt;https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this understanding of mapped types, let us start with some real life uses cases&lt;/p&gt;

&lt;h2&gt;
  
  
  Usecase #1: OmitByType
&lt;/h2&gt;

&lt;p&gt;If you are a typescript dev then you most certainly have used this TS utility called &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys"&gt;Omit&lt;/a&gt;. It helps you to construct a new type from the existing type by removing the keys mentioned in the second parameter of &lt;code&gt;Omit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Take a look at our &lt;code&gt;Vehicle&lt;/code&gt; example with &lt;code&gt;Omit&lt;/code&gt; utility:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&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="s1"&gt;Car&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;noOfWheels&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="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Let us Omit noOfWheels&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OmmitedVehicle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;noOfWheels&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="cm"&gt;/* 
type OmmitedVehicle = {
    type: 'Car',
    color: 'white'
} 
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are removing the property &lt;code&gt;noOfWheels&lt;/code&gt; from &lt;code&gt;Vehicle&lt;/code&gt; i.e. we are removing properties based on a property name. What if we wanted to remove a property based on the type we pass as second argument to &lt;code&gt;Omit&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;For example, we would like to remove all the properties from &lt;code&gt;Vehicle&lt;/code&gt; who’s values are string i.e. remove &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;color&lt;/code&gt; property. &lt;/p&gt;

&lt;p&gt;At this moment TS doesn’t have any such utility to Omit by Type. But we can build this easily with the help of Mapped types and Generics&lt;/p&gt;

&lt;p&gt;Let us first define what we want here. We want are utility to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It should accept 2nd argument that tells the properties to remove based on type.&lt;/li&gt;
&lt;li&gt;Traverse through each property of the type&lt;/li&gt;
&lt;li&gt;If the value of the property is equal to the 2nd argument it should exclude it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But before we start our implementation we should take a look at how the original &lt;code&gt;Omit&lt;/code&gt; utility type works:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nb"&gt;Omit&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;U&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="k"&gt;as&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="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&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;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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It first traverses through each key of the &lt;code&gt;T&lt;/code&gt; type with the help of:&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In terms of our &lt;code&gt;Vehicle&lt;/code&gt; example, K here is the property name that the mapped type will traverse i.e. &lt;code&gt;type&lt;/code&gt; &lt;code&gt;noOfWheels&lt;/code&gt; &lt;code&gt;color&lt;/code&gt;. Next, with the help of &lt;code&gt;as&lt;/code&gt; clause we remap the key such that we exclude the key K if it matches the 2nd parameter of the &lt;code&gt;Omit&lt;/code&gt; Utility. Again if you see the internal working of the &lt;code&gt;Exclude&lt;/code&gt;  utility provided by TS it is as follows:&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="kd"&gt;type&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="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&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;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;U&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="nx"&gt;T&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that if &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;U&lt;/code&gt; matches then it returns &lt;code&gt;never&lt;/code&gt; or else it returns the type &lt;code&gt;T&lt;/code&gt;. This also means that on the match of both the type we don’t want to return anything which is &lt;code&gt;never&lt;/code&gt;. This becomes useful in the &lt;code&gt;Omit&lt;/code&gt; case as follows:&lt;/p&gt;

&lt;p&gt;If key &lt;code&gt;K&lt;/code&gt; in the above mapped type matches with the 2nd parameter i.e. &lt;code&gt;U&lt;/code&gt; then we should not include it in the mapped type. This case can be visualised as follows:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&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="s1"&gt;Car&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;noOfWheels&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="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&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;OmmitedVehicle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;noOfWheels&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="cm"&gt;/*
Internally this happens:

type OmittedVehicle = {

}

which truns into: 

type OmittedVehicle = {

}

and a key in mapped type that is mapped to never becomes excluded from the mapping.
Ideally this would return a blank object like `{}`
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So this gives a new type constructed by omitting properties by name. Getting this understanding was important so that you can easily grasp the concept of our utility: &lt;code&gt;OmitByType&lt;/code&gt;. Here is the utility:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OmitByType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DataType&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;Type&lt;/span&gt; &lt;span class="k"&gt;as&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="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Type&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="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;DataType&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="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;Type&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just watch this utility type carefully. Isn’t it pretty similar to the original &lt;code&gt;Omit&lt;/code&gt; type. Yes, indeed it is but there is a small change which is in the Exclude’s 2nd parameter:&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="nx"&gt;Type&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="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;DataType&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Earlier in the &lt;code&gt;Omit&lt;/code&gt; type we directly put &lt;code&gt;U&lt;/code&gt; as the 2nd parameter to exclude. But here we are doing the following things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Since we are accepting the type to omit is &lt;code&gt;DataType&lt;/code&gt; in our &lt;code&gt;OmitByType&lt;/code&gt; utility, we compare it with the current property’s value. Here the current property is &lt;code&gt;Type[K]&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;If it matches with &lt;code&gt;DataType&lt;/code&gt; we pass this property K to the exclude or else we return never.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Things will get clearer when do the dry run. For the dry run let us again take the &lt;code&gt;Vehicle&lt;/code&gt; example from above:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&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="s1"&gt;Car&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;noOfWheels&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="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&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;OmitByType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DataType&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;Type&lt;/span&gt; &lt;span class="k"&gt;as&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="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Type&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="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;DataType&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="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;Type&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OmittedCarByType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;OmitByType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Vehicle&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the above give code the dry run will look like below:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Value Type&lt;/th&gt;
&lt;th&gt;Condition Check (Value Type extends string?)&lt;/th&gt;
&lt;th&gt;Exclude&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;type&lt;/td&gt;
&lt;td&gt;'Car'&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Exclude type&lt;/td&gt;
&lt;td&gt;Exclude type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;noOfWheels&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Include noOfWheels&lt;/td&gt;
&lt;td&gt;Include noOfWheels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;color&lt;/td&gt;
&lt;td&gt;'white'&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Exclude color&lt;/td&gt;
&lt;td&gt;Exclude color&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This utility type was a solution to the following typescript challenge: &lt;a href="https://github.com/type-challenges/type-challenges/blob/main/questions/02852-medium-omitbytype/README.md"&gt;https://github.com/type-challenges/type-challenges/blob/main/questions/02852-medium-omitbytype/README.md&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Usecase #2: PartialByKeys
&lt;/h2&gt;

&lt;p&gt;This utility is again very similar to the Omit utility. &lt;code&gt;PartialByKeys&lt;/code&gt; will take second argument as union of keys that needs to be made partial/optional in the Type argument T. &lt;/p&gt;

&lt;p&gt;Here is how this utility will look like:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Flatten&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="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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PartialByKeys&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="p"&gt;{},&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&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="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="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&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="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;Partial&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="nx"&gt;Flatten&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Omit&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="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me simplify this a bit and explain you guys the working of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Here we have created a generic utility called &lt;code&gt;PartialByKeys&lt;/code&gt; that take in two arguments &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt;. &lt;code&gt;T&lt;/code&gt; is expected to be of type object and &lt;code&gt;K&lt;/code&gt; is expected to be of keys of &lt;code&gt;T&lt;/code&gt; and is initialised with keys of &lt;code&gt;T&lt;/code&gt; object type.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, we first check that if Keys &lt;code&gt;K&lt;/code&gt; are blank or not. If it is then we should return an object type who’s all the keys are optional.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Notice this syntax here that is used:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight tsx"&gt;&lt;code&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="kd"&gt;extends&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;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;The purpose of using square bracket here is because we don’t want to have &lt;a href="https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types"&gt;distributed conditional types&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;If &lt;code&gt;K&lt;/code&gt; keys are not blank then we should return a new object type with the specified keys as optional/partial.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Here we do a clever trick by separating out the keys that are not needed to be partial we keep it with the help of &lt;code&gt;Omit&amp;lt;T, K&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The ones which we want to make partial we first construct a new object type with the keys that needs to be partial. We do that with the help of &lt;code&gt;Pick&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&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;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next me this entire pick partial with the help of &lt;code&gt;Partial&amp;lt;Pick&amp;lt;T, K&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lastly we combine these both objects into one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quick note: We also make use of Flatten utility so that you can get a clear type annotation instead of a messed up partial + Pick keys&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the Dry run of this Utility with the &lt;code&gt;Vehicle&lt;/code&gt; example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Included in Omit?&lt;/th&gt;
&lt;th&gt;Included in Partial&amp;gt;?&lt;/th&gt;
&lt;th&gt;Final Inclusion&lt;/th&gt;
&lt;th&gt;Optional?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;type&lt;/td&gt;
&lt;td&gt;'Car'&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;noOfWheels&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;color&lt;/td&gt;
&lt;td&gt;'white'&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Usecase #3: PickByType
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;PickByType&lt;/code&gt;, we pick all the properties of object type who’s value matches with the type specified in the utility as the second argument.&lt;/p&gt;

&lt;p&gt;Here is how &lt;code&gt;PickByType&lt;/code&gt; looks like:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PickByType&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;U&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;P&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="k"&gt;as&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;P&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;P&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="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&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 only thing that differentiates this with &lt;code&gt;OmitByType&lt;/code&gt; is the way we make use of the &lt;code&gt;as&lt;/code&gt; clause. Here we make use of &lt;code&gt;as&lt;/code&gt; clause such that only the keys will be shown who value of &lt;code&gt;T[P]&lt;/code&gt; matches with &lt;code&gt;U&lt;/code&gt; i.e. second parameter. &lt;/p&gt;

&lt;p&gt;Here is the dry run of this utility on the &lt;code&gt;Vehicle&lt;/code&gt; type:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Value Type&lt;/th&gt;
&lt;th&gt;Matches string?&lt;/th&gt;
&lt;th&gt;Include Key in Result?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;type&lt;/td&gt;
&lt;td&gt;'Car'&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;noOfWheels&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;color&lt;/td&gt;
&lt;td&gt;'white'&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;At first typescript might look crazy difficult to understand, to follow and might look like some wizardry. But trust me it gets simpler when you learn the basics and start practicing.&lt;/p&gt;

&lt;p&gt;So in this blog post we learned about Mapped types and its crazy ass use cases. We also learned some internal workings of the existing TS utility types such as &lt;code&gt;Omit&lt;/code&gt; and &lt;code&gt;Exclude&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thanks a lot for reading my blogpost.&lt;/p&gt;

&lt;p&gt;You can follow me on &lt;a href="https://twitter.com/keurplkar"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>tutorial</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Simplify Your Code with TypeScript Discriminated Union Types</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Sun, 26 May 2024 07:40:45 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/make-your-life-easy-with-discriminated-union-types-2moi</link>
      <guid>https://forem.com/keyurparalkar/make-your-life-easy-with-discriminated-union-types-2moi</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This will be my first time writing about TS. There are multiple tutorials out there which explain the concept of discriminated unions in an outstanding way. But I will I try my best to explain here my understanding about the concept and how I approached it.&lt;/p&gt;

&lt;p&gt;In this blogpost, we are going to learn about discriminated union types. We will also look at how it is an excellent concept that makes developer’s life less miserable. You will also get to see some realtime examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are discriminated Union Types?
&lt;/h2&gt;

&lt;p&gt;Let me be a good dev and explain this concept by explaining the problem and then the solution. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem Statement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An interface or a type can represent multiple states. And based on these states the other properties in the interface can differ. For example,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A network response has the following structure&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;successful&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;request&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;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"payload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&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;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;failure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;request&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;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&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;p&gt;As you can see, based on the &lt;code&gt;status&lt;/code&gt; property the rest/some of the properties might be present or may note be present.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A general shape interface can have multiple properties that might not be present in all the shapes:&lt;br&gt;
&lt;/p&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Circle'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"radius"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Square'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sideLength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&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;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now their interfaces will look something like below:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/g7j84t?view=editor&amp;amp;module=%2Findex.ts"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now suppose for the Response interface we want to write a utility function that logs the response in different format like below:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/vgx3kz?view=editor&amp;amp;module=%2Findex.ts"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Both of these blocks will have access to the &lt;code&gt;successPayload&lt;/code&gt; and  &lt;code&gt;errorPayload&lt;/code&gt; i.e. we know that type &lt;code&gt;200&lt;/code&gt; means a successful request and we want only to get successPayload and nothing else. Similar is the case for the type &lt;code&gt;400&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The mental model for the types we have is a mapping of status state i.e. &lt;code&gt;type&lt;/code&gt; value with the rest of the parameters. &lt;/p&gt;

&lt;p&gt;As you can see this is a very common problem that all the developers face. To resolve this and tell typescript to distinguish between different values of types we need to make use of Discriminated union types of typescript.&lt;/p&gt;

&lt;h3&gt;
  
  
  Discriminated Union Types
&lt;/h3&gt;

&lt;p&gt;This is a nice little feature that Typescript provides that helps the TS itself to distinguish between which rest of the parameters to choose based on a common property between them. Let us restructure our above example of NetworkResponse interface:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/yg9sls?view=editor&amp;amp;module=%2Findex.ts"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now if we try use the &lt;code&gt;displayNetworkResponse&lt;/code&gt; function we won’t get any type errors.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/vljmcs?view=editor&amp;amp;module=%2Findex.ts"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Realtime Use case
&lt;/h2&gt;

&lt;p&gt;I have always faced this issue while using the React’s Context APIs where I have my actions ready with me and each and every action would have a different &lt;code&gt;payload&lt;/code&gt; property. But when I am building my reducer function I don’t get the narrowed typing based on the action case I am in inside the switch case. Let me demonstrate this with an example.&lt;/p&gt;

&lt;p&gt;Suppose you have these set of actions with you:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/353862?view=editor&amp;amp;module=%2Fsrc%2Fstore%2Factions.ts"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;These are simple actions like adding and removing a TODO from a list&lt;/p&gt;

&lt;p&gt;Next, we define the action creators or the functions that dispatch the action like below:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ACTIONS&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;./actions&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;addTodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ACTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ADD_TODO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;removeTodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;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="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="nx"&gt;ACTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REMOVE_TODO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we see here the &lt;code&gt;payload&lt;/code&gt; attribute of both the actions is different. For &lt;code&gt;ADD_TODO&lt;/code&gt; action the payload attribute consists of &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt; and for &lt;code&gt;REMOVE_TODO&lt;/code&gt; action we just pass an &lt;code&gt;id&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Now let us define our reducer function like below:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ACTIONS&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;./actions&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;reducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&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="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ACTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ADD_TODO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ACTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;REMOVE_TODO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both the action cases TS is not able to decide the types for the payload. It will display typings as follows:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&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;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text&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;|&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;number&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 this is not what we want. We expect that when the &lt;code&gt;ADD_TODO&lt;/code&gt; action is being used as the &lt;code&gt;payload&lt;/code&gt; attribute then it should consists of &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt; attribute and for &lt;code&gt;REMOVE_TODO&lt;/code&gt; we expect that it should consists of only the &lt;code&gt;id&lt;/code&gt; attribute. How can typescript know this mapping? Discriminated Union Types to the rescue.&lt;/p&gt;

&lt;p&gt;We need to return the &lt;code&gt;ActionTypes&lt;/code&gt; type from the actions file like below:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/353862?view=editor&amp;amp;module=%2Fsrc%2Fstore%2FactionCreators.ts"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ActionTypes&lt;/code&gt; here is a type that will be a union of return type of &lt;code&gt;addTodo&lt;/code&gt; and &lt;code&gt;removeTodo&lt;/code&gt; function. Here the common property to discriminated will be the &lt;code&gt;type&lt;/code&gt; property in both function’s return type. Now making use of this type inside the &lt;code&gt;reducer&lt;/code&gt; function like below, helps us to achieve what we wanted:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/353862?view=editor&amp;amp;module=%2Fsrc%2Fstore%2Freducers.ts"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now if you check the payload attribute in each section then we are able to see that payload types are getting changed based on the action type.&lt;/p&gt;

&lt;p&gt;So this is the magic of Discriminated Union Types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I feel discriminated union type is the most underrated feature for typescript. I believe every developer should use it to have better type narrowing that will help to write better and predictable code.&lt;/p&gt;

&lt;p&gt;Thanks a lot for reading my blogpost.&lt;/p&gt;

&lt;p&gt;You can follow me on &lt;a href="https://twitter.com/keurplkar"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>redux</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build a Realtime Collaborative Whiteboard with Supabase &amp; React</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Sat, 11 May 2024 17:34:21 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/mastering-real-time-collaboration-building-figma-and-miro-inspired-features-with-supabase-57eh</link>
      <guid>https://forem.com/keyurparalkar/mastering-real-time-collaboration-building-figma-and-miro-inspired-features-with-supabase-57eh</guid>
      <description>&lt;p&gt;Have you guys every tried to use figma or miro? If you have used it then I am pretty sure you might have seen this feature where all of a sudden you start to see multiple cursors on your figma file or miro board. If you haven’t seen this ever yet, here is the quick video of what I am talking about.&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2F7mw2fxm3628lwnuoqgn9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F7mw2fxm3628lwnuoqgn9.gif" alt="Figma's Realtime Experience"&gt;&lt;/a&gt;Figma's Realtime Experience
  

&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2F6x4312kqvoqz0uxu5way.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F6x4312kqvoqz0uxu5way.gif" alt="Miro's Realtime Experience"&gt;&lt;/a&gt;Miro's Realtime Experience
  

&lt;/p&gt;

&lt;p&gt;Isn’t it sleek. I mean just look at it, it looks so cool. Can you imagine how they must have build this feature? What did it take to build this to provide such a good dynamic user experience? Bye bye screen share, just follow that persons cursor and here to the audio in the meeting and you are good to go.&lt;/p&gt;

&lt;p&gt;I just love this feature. So I set out on a quest on understanding the feature and what would it take to build such a feature. I must say it was really a pain to understand it TBH but things got way easier later. So let us dive deeper into the understanding and implementing this project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The What?
&lt;/h2&gt;

&lt;p&gt;We are trying to build sticky notes board application, in which we are able to see multiple cursors and sticky notes as a status of what other users are doing on the same website. In this project every user has the information about all the other users, like where their cursor is moving, what they are typing, which note they are dragging etc.&lt;/p&gt;

&lt;p&gt;To give you guys an idea here is the video that shows the application in action:&lt;/p&gt;

&lt;p&gt;

Realtime App in action
  

&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To get the most out of this blog post, I highly recommend that you guys be familiar with the below topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;Typescript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://supabase.com/docs" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Why?
&lt;/h2&gt;

&lt;p&gt;So I know and this question might have arrived to you as to why are we doing this. We are doing this because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To gain insights on how innovative UX works.&lt;/li&gt;
&lt;li&gt;Understand some critical UX decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Some backstory
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2F54rqy5nq9va0yl0xfw23.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F54rqy5nq9va0yl0xfw23.gif" alt="GTA:SA Meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So before we dive into the implementation, I would like to share a few things about this project(my personal exp.). During this project I studying a ton about webRTC. I started studying &lt;a href="https://webrtc.org/" rel="noopener noreferrer"&gt;webRTC&lt;/a&gt; from scratch, like what is webRTC? how is the connection formed? how the data transfer takes place.&lt;/p&gt;

&lt;p&gt;I took this decision of choosing webRTC because I thought each client needs information about every other client connected over the network/room. So isn’t this same as the video conferencing apps like Microsoft Teams, Zoom, Google Meet etc. In these apps, every client knows about every other client and they share the stream of data directly with the help of webRTC(that’s what I thought). But it turns out it’s not that simple, this would create a mesh kind of a network and would be resource intensive over the network. So there are better protocols/patterns to handle such cases like &lt;a href="https://bloggeek.me/webrtcglossary/sfu/" rel="noopener noreferrer"&gt;SFU(Selective Forwarding Unit)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ok I went too back, but you guys get the point right. So I though it’s just a simple project. rather than having multiple streams of video shared between each other I just need to replace it with the cursor position of every other client. How hard can it be right? actually its very hard.&lt;/p&gt;

&lt;p&gt;I tried to first implement the webRTC full mesh pattern just to understand how every client would share their stream with others. But managing the connection i.e. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Perfect_negotiation" rel="noopener noreferrer"&gt;offer negotiation in webrtc&lt;/a&gt; got way tricky when more than 2 clients came in so I dropped the idea.&lt;/p&gt;

&lt;p&gt;So instead, I pivoted and moved on to what supabase’s realtime DB does. I actually used it in this project. Yeah, so that was the backstory but let’s continue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The How?
&lt;/h2&gt;

&lt;p&gt;This is the part where we understand the implementation of the entire project. I have used the following tech stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For Frontend - React.js and Vite&lt;/li&gt;
&lt;li&gt;For Backend - Supabase&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before getting into the frontend, let us understand what the backend is and how it helps us to achieve our results.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;NOTE:&lt;/strong&gt; This blog post is not going to be a step-by-step guide but rather a walk through to the codebase along with the detailed explanation of the concepts/architecture&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Enter Supabase
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt; is a backend as a service visual platform that allows you to create postgres DB with minimum code. Their documentation is so good that it feels like home and you can get your project online in no matter of time.&lt;/p&gt;

&lt;p&gt;So this cool low-code no-code platform provides a &lt;a href="https://supabase.com/realtime" rel="noopener noreferrer"&gt;realtime feature&lt;/a&gt; that lets you do a bunch of stuffs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listen to updates to the DB inserts, updates and any other changes&lt;/li&gt;
&lt;li&gt;Update your frontend state globally with &lt;a href="https://supabase.com/docs/guides/realtime/presence" rel="noopener noreferrer"&gt;Presence API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;You can also broadcast your changes to all the connected clients.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Out of these 3 we are going to make use of the Presence API. &lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;p&gt;So let us look at the things we need to build our Sticky notes board app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We need a way to have a live cursor feel i.e. my screen should also show where other folks are moving their cursors&lt;/li&gt;
&lt;li&gt;We also need a way to let my screen know that what others are doing like, adding a note and moving the note&lt;/li&gt;
&lt;li&gt;If any of the folks closes their browser window, then my screen shouldn’t contain changes from the guy who left.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these requirements can be achieved using the &lt;a href="https://supabase.com/docs/guides/realtime/presence" rel="noopener noreferrer"&gt;Supabase’s Presence API&lt;/a&gt;. It is the perfect recipe to achieve our thing.&lt;/p&gt;

&lt;p&gt;Before we start going in depth on this API we first need to understand what channels are.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Channels:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is the basic building block of the realtime feature.&lt;/li&gt;
&lt;li&gt;Channel is where all the clients connect to. Imagine that Channel is nothing but a room where all the people can join in.&lt;/li&gt;
&lt;li&gt;Whenever a new client comes in, we need to make sure that it connects to this room/channel.&lt;/li&gt;
&lt;li&gt;You can find details regarding the same &lt;a href="https://supabase.com/docs/guides/realtime/concepts#channels" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Now let us understand the Presence API. It is an API that helps you share your current client state with all the other clients. It does that with the help of the &lt;code&gt;track&lt;/code&gt; function. So a typical track function call will look like below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;room1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// creates a channel 'room1' &lt;/span&gt;

&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&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;Each channel has a common pool of states for all the clients. Now if a user, suddenly closes his tab i.e. if the client is removed from the channel then this state is also updated. We will look at the details of the other events like &lt;code&gt;join&lt;/code&gt; &lt;code&gt;leave&lt;/code&gt; and &lt;code&gt;sync&lt;/code&gt; of the presence API in the later section of this blog post. &lt;/p&gt;

&lt;p&gt;Now that we know the presence API, so let us start off our journey to understanding the project architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;A little detour here, I would like to talk about the frontend tooling/project environment here. From the frontend standpoint I am using Vite to create the project scaffoldings. I have used a typescript template of Vite since the project is build with typescript.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create vite &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Make use of the above command to create a &lt;a href="https://vitejs.dev/guide/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; project with react based typescript template.&lt;/p&gt;

&lt;p&gt;From the backend standpoint, I am making use of supabase’s local setup. I won’t be covering that in this blog post because supabase guide has done a pretty nice job at explaining it &lt;a href="https://supabase.com/docs/guides/cli/getting-started" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Other libraries used are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supabase-js: This is the client side wrapper of supabase. You can read more about it &lt;a href="https://supabase.com/docs/reference/javascript/introduction" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nonoid: A library that helps you to generate unique string ids. Read the full documentation here&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Project Architecture
&lt;/h3&gt;

&lt;p&gt;So we are all set from the project setup standpoint. So let us now understand by how the flow of the application would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whenever a new tab is opened with our project on our browser that means we need to create a new client instance of supabase. So we start by creating a client.&lt;/li&gt;
&lt;li&gt;Next, we create a channel so that the client gets added to that channel&lt;/li&gt;
&lt;li&gt;We listen for the &lt;code&gt;sync&lt;/code&gt; and &lt;code&gt;leave&lt;/code&gt; events of the Presence API&lt;/li&gt;
&lt;li&gt;On update of user activity we need to pass this data to all the other clients&lt;/li&gt;
&lt;li&gt;If the browser window is closed, we need to make sure that all the clients won’t contain data related to the removed client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fvdsrbpvrr1bv46esfcj0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fvdsrbpvrr1bv46esfcj0.png" alt="Project Architecture"&gt;&lt;/a&gt;Project Architecture
  

&lt;/p&gt;

&lt;p&gt;After gaining this knowledge of the application flow we are in a good state to understand the implementation details. As I mentioned earlier since this is not going to be a step-by-step code walkthrough but an in depth core understanding blog post.&lt;/p&gt;

&lt;p&gt;Now let us familiarise ourselves with the repository structure:&lt;/p&gt;

&lt;p&gt;There are 3 files that we need to carefully look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;App.tsx&lt;/code&gt; - The driver program where entire logic resides&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;component/Cursor.tsx&lt;/code&gt; - An SVG cursor component to show the pointer of the other clients&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;component/StickyNote.tsx&lt;/code&gt; - A component to show the stickynote that is editable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will go through each and every file to understand the application flow:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I would highly recommend to open each file while you are reading the details of each file structure. In that way you won’t get lost. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  App.tsx
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Refer to this &lt;a href="https://github.com/keyurparalkar/realtime-whiteboard-app/blob/main/src/App.tsx" rel="noopener noreferrer"&gt;component&lt;/a&gt; while reading the below section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;This file will get loaded as soon as the browser tab hits our project URL. So according to the flow we should instantiate a supabase client which we do it like below:&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SUPABASE_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;You can read more about &lt;code&gt;createClient&lt;/code&gt; function here: &lt;a href="https://supabase.com/docs/reference/javascript/initializing" rel="noopener noreferrer"&gt;https://supabase.com/docs/reference/javascript/initializing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Once the client is instantiated, we expect that it should create a channel like below:&lt;/p&gt;

&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;clientA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;room-1&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;ul&gt;
&lt;li&gt;For a new client it will check that the channel with &lt;code&gt;room-1&lt;/code&gt; exists or not. If it exists, it joins the channel or else create one.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;On mount of our main app here: , we expect the client to subscribe to the presence API’s &lt;code&gt;sync&lt;/code&gt; and &lt;code&gt;leave&lt;/code&gt; events. To do this we first create the event handlers that listen to these events like below:&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&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;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;presence&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;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sync&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;presenceState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Clients&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                &lt;span class="c1"&gt;// code to manage the state once other client updates&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&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;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;clientId&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;&amp;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;presence&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;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leave&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;leftPresences&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// code to manage the state when any user leaves&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="nx"&gt;removeClient&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Upon adding these event handlers we then subscribe them along like below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isFirstRender&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="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;subsChannel&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;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="nx"&gt;isFirstRender&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;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="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This effect will execute on mount of the component. We also need to make sure that we don’t accidentally call the &lt;code&gt;subscribe&lt;/code&gt; method more than once or else supabase will throw an error. This issue won’t happen in production but in strict mode i.e. in development mode this effect would run twice. That’s the react’s way to make sure that things are predictable.&lt;/p&gt;

&lt;p&gt;So to avoid this, I added a ref &lt;code&gt;isFirstRender&lt;/code&gt;. It gets set to false when the effect runs the second time in strict mode.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is one thing to take note of and that is the structure of the data that we are syncing between all the clients. It is as follows:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;EventTypes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;MOVE_MOUSE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;move-mouse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;MOVE_NOTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;move-note&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;ADD_NOTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;add-note&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;ADD_NOTE_TEXT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;add-note-text&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;type&lt;/span&gt; &lt;span class="nx"&gt;Note&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;x&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;y&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;content&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;type&lt;/span&gt; &lt;span class="nx"&gt;Payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventTypes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;x&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;y&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;color&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;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Note&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;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Clients&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="nx"&gt;Payload&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;These are the typescript types but they translate to something like below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;span class="nl"&gt;"W3lf6J4shQUfE-DTkILBb"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rgb(15%, 30%, 40%)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"move-mouse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;829&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;235&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"notes"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is note from client W3lf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;202&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;350&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;span class="p"&gt;]&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;span class="nl"&gt;"JRlR_3qHr7B2bad2HVvWE"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rgb(94%, 30%, 40%)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"move-mouse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"notes"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This note from client JRIR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;198&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;729&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;span class="p"&gt;]&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;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;This would be a typical state that each client will hold. We also tell each client to hold the states of all the other clients as well which happens in the &lt;code&gt;newClients&lt;/code&gt; state variable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Now let us understand how each client get synced with all the other clients. Each client has 3 points where they update their own state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the mouse move happens,&lt;/li&gt;
&lt;li&gt;When the note is added &amp;amp;&lt;/li&gt;
&lt;li&gt;When the sticky note is moved.&lt;/li&gt;
&lt;li&gt;When the sticky note is edited&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whenever any of these scenarios happen we call their respective event handlers. So as you expect, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For the mouse move we would use &lt;code&gt;onMouseMove&lt;/code&gt; ,&lt;/li&gt;
&lt;li&gt;When note is added we use &lt;code&gt;onClick&lt;/code&gt; of the &lt;code&gt;button&lt;/code&gt; present on the screen,&lt;/li&gt;
&lt;li&gt;For editing of sticky note, the &lt;code&gt;onChange&lt;/code&gt; event of sticky note component is used.&lt;/li&gt;
&lt;li&gt;And finally when the note is moved we use &lt;code&gt;onMouseMove&lt;/code&gt; of the StickyNote component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And for all these scenarios they update their states with the help of &lt;code&gt;channel.track&lt;/code&gt; function. It is a presence API function that send the update to all the other clients connected to the channel. You can read more about this function &lt;a href="https://supabase.com/docs/guides/realtime/presence#sync-and-track-state" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Now to make our scenarios work, we make use of the following event handlers:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleMouseMove&lt;/span&gt; &lt;span class="o"&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="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&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="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;throttledChannelTrack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CURRENT_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;newClients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CURRENT_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="na"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MOVE_MOUSE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;randomColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;x&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;clientX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;y&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;clientY&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleNoteAddition&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newClients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CURRENT_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

            &lt;span class="c1"&gt;// We want to add notes immediately, hence not using throttled version of track():&lt;/span&gt;
            &lt;span class="nx"&gt;subsChannel&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;track&lt;/span&gt;&lt;span class="p"&gt;?.({&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CURRENT_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ADD_NOTE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notes&lt;/span&gt;
                        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_NOTE&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;DEFAULT_NOTE&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleNoteMouseMove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;noteIndex&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="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newClients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CURRENT_CLIENT_ID&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;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;noteIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentNote&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="nf"&gt;throttledChannelTrack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CURRENT_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MOVE_NOTE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Notice the &lt;code&gt;throttledChannelTrack&lt;/code&gt; function. It is a throttle function, used only for frequently happening events such as mouse move and sticky note moves. For scenarios like note addition we directly make use of the &lt;code&gt;channel.track&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CURRENT_CLIENT_ID&lt;/code&gt; is the random unique string Id generated by &lt;a href="https://github.com/ai/nanoid" rel="noopener noreferrer"&gt;nanoid&lt;/a&gt; that gets generated whenever the client is opened on the brower’s tab.&lt;/p&gt;

&lt;p&gt;It’s nice to observe that on each track call we update the current client’s state and also keep its existing state as well.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once the track function is called, then immediately the presence API’s &lt;code&gt;sync&lt;/code&gt; event handler gets executed. It is the general working of the API that whenever a track call happens &lt;code&gt;sync&lt;/code&gt; event handler gets executed. So now if the current client does any of the above scenarios, it will call the track function with the above payload and execute the &lt;code&gt;sync&lt;/code&gt; event handler.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case, we need to make sure that we do the following things when this event handler executes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Capture the `presenceState` from the channel. This is a state that the channel maintains that consists of all the latest updates(presence events) made from all the other clients.
- Iterate through all the presence events and update the `newClients` state with all these presence events.
- What we are doing here is, all the presence event is nothing but each client’s own state from all the other clients. We are just capturing all the other clients state into the current client and updating it in a state variable called `newClients`.
- In this way, we keep track of other clients:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&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;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;presence&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;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sync&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;presenceState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Clients&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="na"&gt;presenceValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Clients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

                &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;stateId&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;presenceValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;stateId&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presenceValue&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="nx"&gt;presenceValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;presenceValue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;

                &lt;span class="nf"&gt;setNewClients&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;preValue&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;updatedClients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presenceValues&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Clients&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;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;curr&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;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;curr&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="nx"&gt;preValue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;curr&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                                &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;presenceValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;curr&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;acc&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;updatedClients&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;One last thing that I would like to discuss here, is the updating the UI whenever a client is removed. We don’t want our UI to get cluttered from the sticky notes from the clients who have left the channel. Have a look at this video to get clear understanding of what I am saying:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Faae94250-4c41-465d-922a-bdbed4531c8f%2F67ed623d-5183-4431-9f48-b709786c039d%2FClient_removed.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Faae94250-4c41-465d-922a-bdbed4531c8f%2F67ed623d-5183-4431-9f48-b709786c039d%2FClient_removed.gif" alt="Client_removed.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is pretty easy to achieve. We just need to add an event handler for the &lt;code&gt;leave&lt;/code&gt; event of the presence API and update the &lt;code&gt;newClients&lt;/code&gt; state variable with the current &lt;code&gt;sync&lt;/code&gt; state between the clients. Here is the code for it:&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&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;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;clientId&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;&amp;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;presence&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;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leave&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;leftPresences&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;leftPresences&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="nf"&gt;removeClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;removeClient&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 it for the entire application logic. Let us now take a brief look on the UI components. UI components are pretty straight forward. They would taken a bunch of props and display it in a good manner.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor.tsx
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Refer to this &lt;a href="https://github.com/keyurparalkar/realtime-whiteboard-app/blob/main/src/components/Cursor.tsx" rel="noopener noreferrer"&gt;component&lt;/a&gt; while reading this component&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This component would take in the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinates and the name of the client and show them in a good nelly welly way. Have a look at the below cursor image:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fp6fer20zoml3s63qsabx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fp6fer20zoml3s63qsabx.png" alt="Custom Cursor"&gt;&lt;/a&gt;Custom Cursor
  

&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A quick thing to note about this component is that, it will render all the cursors expect for the current client/browser window. This is a UI descision that I took. I took this decision because we don’t want to show another pointer apart from the current pointer that we see i.e. the actual one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  StickyNote.tsx
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Refer to this &lt;a href="https://github.com/keyurparalkar/realtime-whiteboard-app/blob/main/src/components/StickyNote.tsx" rel="noopener noreferrer"&gt;component&lt;/a&gt; while reading this component&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This component simply renders all the notes in that are stored in the &lt;code&gt;newClients&lt;/code&gt; state variable. It takes in the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinate of the current note and the content inside it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One important thing about this sticky note is that even for the current client we show it’s note. This makes sense right because we want to know and see that we added a sticky note and it should appear on the screen hence this decision.&lt;/li&gt;
&lt;li&gt;This component add a bit of jazz to the entire flow. What it would do is, it will highlight the notes from the other clients onto your screen. Your current sticky notes won’t be highlighted. In this way, we make clear distinction as to which note belongs to whom. Have a look at this small video/gif:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fl58405ibadvddokrnowb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fl58405ibadvddokrnowb.png" alt="Sticky Notes component"&gt;&lt;/a&gt;Sticky Notes Component
  

&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can even see that the color of the cursor matches with the highlights of the sticky notes for the clients that are external to the current clients.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This project gave me good learnings. Below are some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use a callback function with the setter to update state variables effectively, avoiding infinite renders caused by placing state updates in useEffect hooks triggered by dependency changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid initializing state variables with props to prevent potential issues where subsequent prop changes are not reflected. Instead, update the state when props change to ensure accurate data representation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall in this blog we looked at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why are we doing this project&lt;/li&gt;
&lt;li&gt;Understood the backstory&lt;/li&gt;
&lt;li&gt;Project Architecture&lt;/li&gt;
&lt;li&gt;Presence API&lt;/li&gt;
&lt;li&gt;UI components: Cursor and Sticky notes&lt;/li&gt;
&lt;li&gt;Hiding the cursors and highlighting sticky notes for better user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire codebase for this project can be found &lt;a href="https://github.com/keyurparalkar/realtime-whiteboard-app" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;Follow me on &lt;a href="https://twitter.com/keurplkar" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar" rel="noopener noreferrer"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/" rel="noopener noreferrer"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Rendering a Million Rows in React by Drawing</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Sat, 23 Mar 2024 13:28:23 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/rendering-a-million-rows-in-react-by-drawing-1a39</link>
      <guid>https://forem.com/keyurparalkar/rendering-a-million-rows-in-react-by-drawing-1a39</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A couple of weeks ago, I stumbled upon a challenge known as the &lt;a href="https://www.google.com/search?q=one+billion+row+challenege+golan&amp;amp;oq=one+billion+row+challenege+golan&amp;amp;gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIJCAEQABgNGIAE0gEJMTMwNTlqMGo3qAIAsAIA&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8#ip=1" rel="noopener noreferrer"&gt;one billion row challenge&lt;/a&gt;. I found it intriguing from two perspectives:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What would happen if I attempted this challenge on the front end?&lt;/li&gt;
&lt;li&gt;Can I accomplish it?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I don’t believe we can render billions of rows onto a table, but I do think we can handle a million. That’s correct. After reading about the aforementioned challenge, I embarked on a small mini-project to render a million rows in React.&lt;/p&gt;

&lt;p&gt;Let me provide you with a detailed account of what happened, how it happened, and why 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;I recommend you folks to go through the below topics to have a better grasp of the topic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas" rel="noopener noreferrer"&gt;Canvas Element&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" rel="noopener noreferrer"&gt;Canvas API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D" rel="noopener noreferrer"&gt;Render context&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes" rel="noopener noreferrer"&gt;Drawing basic shapes on canvas&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The What?
&lt;/h2&gt;

&lt;p&gt;What we are trying to build is a component that will help us to render a million rows in a ReactJs App. We make use of several techniques that are being used by other products such as &lt;a href="https://www.google.com/sheets/about/" rel="noopener noreferrer"&gt;google sheets&lt;/a&gt; and &lt;a href="https://github.com/glideapps/glide-data-grid" rel="noopener noreferrer"&gt;glide data grid app&lt;/a&gt; to achieve it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Why?
&lt;/h2&gt;

&lt;p&gt;I explained why I did this in the above introduction section but there are more reasons for it. &lt;/p&gt;

&lt;p&gt;I think everyone might have encountered a scenario where they use virtualization to render only the rows in the table's viewport. This is a pretty common use case i.e. to render a lot of data via this technique.&lt;/p&gt;

&lt;p&gt;But this technique can get slightly frisky/risky when you set the window size to be large i.e. 150 to 250 rows that need to be viewed in a single go. This tells the virtualization algorithm for these many rows to do this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove all the DOM elements in the viewport&lt;/li&gt;
&lt;li&gt;Then add the next set of 150+ DOM elements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While doing this on scroll this operation can get pretty expensive and can bog the main thread leading to a laggy user experience.&lt;/p&gt;

&lt;p&gt;Apart from this I also explored other tools and libraries such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.google.com/sheets/about/" rel="noopener noreferrer"&gt;Google Sheets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/glideapps/glide-data-grid" rel="noopener noreferrer"&gt;Glide Data Grid&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They have done a pretty good job of rendering a million rows. &lt;/p&gt;

&lt;p&gt;Now you know these reasons, so let us understand the uncommon way to solve this common problem.&lt;/p&gt;

&lt;p&gt;💡 NOTE: This is a blog to explain all the key concepts required to build this project. You can have a look at the entire code in this &lt;a href="https://github.com/keyurparalkar/render-million-rows" rel="noopener noreferrer"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The How?
&lt;/h2&gt;

&lt;p&gt;To implement this, we will be taking the approach of drawing instead of rendering a table. In this, we will draw every data row with the help of the canvas element. &lt;/p&gt;

&lt;p&gt;Canvas HTML element is the go-to element for any drawing stuff. Its &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D" rel="noopener noreferrer"&gt;context APIs&lt;/a&gt; provide many functions that can help you to draw any shape that you like. &lt;/p&gt;

&lt;p&gt;Now we know what are we going to use, therefore let us understand the implementation steps. The implementation is divided into 3 simple parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loading the Data&lt;/li&gt;
&lt;li&gt;Initializing the Canvases&lt;/li&gt;
&lt;li&gt;Drawing the data on a scroll&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will go into every step and understand them. To keep this blog simple, I will try to explain all the above steps visually and will keep the coding part to a minimum.&lt;/p&gt;

&lt;p&gt;I expect that you guys can go through the code and have a look at it from the above note section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initializing the Project
&lt;/h3&gt;

&lt;p&gt;I make use of the Reactjs project starter kit: &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite.js&lt;/a&gt;. It will help you to create scaffoldings for your project&lt;/p&gt;

&lt;p&gt;I have made use of the &lt;code&gt;typescript&lt;/code&gt; template, to do the same follow this tutorial: &lt;a href="https://vitejs.dev/guide/#scaffolding-your-first-vite-project" rel="noopener noreferrer"&gt;https://vitejs.dev/guide/#scaffolding-your-first-vite-project&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, please refer to the repository which contains the full code for the project to familiarize yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loading the Data
&lt;/h3&gt;

&lt;p&gt;

&lt;a href="https://media.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%2F0hur7yvzixsp9yfi7owj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F0hur7yvzixsp9yfi7owj.png" alt="loading_the_data_ui"&gt;&lt;/a&gt;UI for loading the data
  

&lt;/p&gt;

&lt;p&gt;This step involves the creation of a couple of buttons that download the data from the remote source. So on the UI, we have 4 buttons that download the same data with different numbers of rows i.e. 100, 0.5M, 1M, and 2M rows respectively.&lt;/p&gt;

&lt;p&gt;At the click of a button, the data is downloaded and parsed into an array of objects with the help of &lt;a href="https://github.com/mholt/PapaParse" rel="noopener noreferrer"&gt;papa-parse&lt;/a&gt; library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the DOM structure
&lt;/h3&gt;

&lt;p&gt;Before we jump into the next steps, I would like to take a step back here and explain the DOM structure of the table that we are going to draw. &lt;/p&gt;

&lt;p&gt;It will just look like a normal table, like below:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fbvmr6ruho3x1eo4osp3j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fbvmr6ruho3x1eo4osp3j.png" alt="Table UI"&gt;&lt;/a&gt;Table UI
  

&lt;/p&gt;

&lt;p&gt;It just feels like a normal table with a header and rows and scrollbars.&lt;/p&gt;

&lt;p&gt;This image of the table is divided into the following parts such that each part represents that DOM element in the project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;header-canvas&lt;/code&gt; - It is the canvas element on which we draw the table’s header.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;target-canvas&lt;/code&gt; - It is the canvas element on which the table’s actual rows are drawn&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scrollbar-container&lt;/code&gt; - It is a div element that provides the dummy scrollbar to the &lt;code&gt;main-container&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main-container&lt;/code&gt; - A div element that wraps both the &lt;code&gt;header-canvas&lt;/code&gt;, &lt;code&gt;target-canvas&lt;/code&gt;, and the &lt;code&gt;scrollbar-container&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To give the exact overview of these elements here is the gif:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fgziyrrrc4c08k22feui4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fgziyrrrc4c08k22feui4.gif" alt="DOM Structure Disassembled"&gt;&lt;/a&gt;DOM Structure Disassembled
  

&lt;/p&gt;

&lt;p&gt;You can look at the DOM structure from a code standpoint &lt;a href="https://github.com/keyurparalkar/render-million-rows/blob/0bd6442ba8e9a62c65f3fa50e387fdc282a5000b/src/App.tsx#L266" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initializing the Canvases
&lt;/h3&gt;

&lt;p&gt;Now that we got to know what is what, let us dive into the step of initializing both canvases. We do the following steps to initialize:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Whenever the component is mounted we initialize a web worker like below:&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
     * On component mount, initialze the worker.
     */&lt;/span&gt;
    &lt;span class="nf"&gt;useEffect&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;if &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;Worker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Refer to the Vite's Query Suffix syntax for loading your custom worker: https://vitejs.dev/guide/features.html#import-with-query-suffixes&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomWorker&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;workerRef&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;worker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, when the CSV data is available we run the effect that updates the &lt;code&gt;header-canvas&lt;/code&gt; and then pass on the &lt;code&gt;target-canvas&lt;/code&gt; to the &lt;code&gt;webworker&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
     * This effect runs when the downloaded data becomes available.
     * It has the following purpose:
     * 1. Draw the table header on #header-canvas
     * 2. Transfer the control to the worker
     */&lt;/span&gt;
    &lt;span class="nf"&gt;useEffect&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;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvasRef&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headerCanvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerCanvasRef&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;headerCanvas&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;headerContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerCanvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2d&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;width&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_CELL_DIMS&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;colNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CustomerDataColumns&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;headerContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;headerContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;strokeStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nx"&gt;headerContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bold 18px serif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="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;DEFAULT_COLUMN_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="nx"&gt;headerContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#242424&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="nx"&gt;headerContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&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="nx"&gt;width&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="nx"&gt;width&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;headerContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="nx"&gt;headerContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strokeRect&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="nx"&gt;width&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="nx"&gt;width&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;headerContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colNames&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;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;10&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="cm"&gt;/**
         * We transfer two things here:
         * 1. We convert our #canvas that draws the actual table to an offscreen canvas
         * 2. We use the transfer the above canvas to the worker via postMessage
         */&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;workerRef&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;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;csvData&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;canvas&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;mainOffscreenCanvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transferControlToOffscreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;workerRef&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="nf"&gt;postMessage&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;generate-data-draw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;targetCanvas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mainOffscreenCanvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;csvData&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;mainOffscreenCanvas&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;csvData&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A thing to note here is that we convert the &lt;code&gt;target-canvas&lt;/code&gt; into an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas" rel="noopener noreferrer"&gt;offscreencanvas&lt;/a&gt;. An offscreen canvas is similar to a canvas element but it is decoupled from the DOM. You can even create the canvas with the &lt;code&gt;new&lt;/code&gt; keyword and pass it on to the worker. &lt;/p&gt;

&lt;p&gt;The fun fact about offscreen canvas is that, it is also available inside the worker’s context. In this way, it also allows to use of the canvas’s context API from the worker. &lt;/p&gt;

&lt;p&gt;In our case, we converted the &lt;code&gt;target-canvas&lt;/code&gt; to an &lt;code&gt;offscreen&lt;/code&gt; canvas with the help of &lt;code&gt;transferControlToOffscreen&lt;/code&gt; function(read &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/transferControlToOffscreen" rel="noopener noreferrer"&gt;here&lt;/a&gt;). By this, If I try to draw a rect with &lt;code&gt;fillRect&lt;/code&gt; function of the context API from the worker , then it appears here on the main canvas which is present in the DOM.&lt;/p&gt;

&lt;p&gt;To read more about the offscreen canvas API, read &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2F0qit8sell18wjs60iz6m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F0qit8sell18wjs60iz6m.png" alt="Pictorial Summary of What we are doing in this Step."&gt;&lt;/a&gt;Pictorial Summary of What we are doing in this Step.
  

&lt;/p&gt;

&lt;h2&gt;
  
  
  Big Brain Time
&lt;/h2&gt;

&lt;p&gt;Buckle up, guys!! because in this section there is going to be a lot of understanding and grasping of the concepts so that you can understand the codebase in the project.&lt;/p&gt;

&lt;p&gt;This section will talk about the entire mechanism of drawing the data onto the &lt;code&gt;target-canvas&lt;/code&gt; while you are scrolling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the &lt;code&gt;Scrollbar-container&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;So first let us understand our special container i.e. the &lt;code&gt;scrollbar-container&lt;/code&gt; that we talked about in the above section. &lt;/p&gt;

&lt;p&gt;So a normal &lt;code&gt;div&lt;/code&gt; element will have scrollbars if it has its &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; property to be set to &lt;code&gt;x&lt;/code&gt; px i.e. static values along with its children’s height exceeding this parent &lt;code&gt;height&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;But let me ask you guys a question: &lt;em&gt;Have you ever encountered a scenario where you don’t have any overflowing content inside the &lt;code&gt;div&lt;/code&gt; but still want the scrollbars?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are a couple of solutions like: &lt;em&gt;using custom scrollbar libraries such as &lt;a href="https://github.com/Grsmto/simplebar/tree/master" rel="noopener noreferrer"&gt;simplebar&lt;/a&gt;, or &lt;a href="https://kingsora.github.io/OverlayScrollbars/" rel="noopener noreferrer"&gt;OverlayScrollbars&lt;/a&gt;.&lt;/em&gt; So even though u make use of these libs there is still a scenario of by how much height you want to scroll your container i.e. having a custom scrollable height to your div.&lt;/p&gt;

&lt;p&gt;But how would we achieve such functionality? It’s way simpler than you think. I learned this trick when I was exploring the Google Sheets which had 0.5M rows. &lt;/p&gt;

&lt;p&gt;In google-sheets, they have a &lt;code&gt;div&lt;/code&gt; element of width equal to &lt;code&gt;1px&lt;/code&gt; but the height of this div is equal to the &lt;code&gt;rows*rowHeight&lt;/code&gt;. In Google Sheets, this &lt;code&gt;div&lt;/code&gt; was placed inside its parent container. This helped them to achieve the a custom scrollable height with the content is overflowing.&lt;/p&gt;

&lt;p&gt;So I used the same approach of using this dummy div, with &lt;code&gt;width = 1px&lt;/code&gt; and &lt;code&gt;height = rows*rowHeight&lt;/code&gt;. And this is what the &lt;code&gt;scrollbar-container&lt;/code&gt; comprises off. &lt;/p&gt;

&lt;p&gt;Here is the pictorial representation of the scrollbar-container:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2F7uhp1zi5icwmsinbr5us.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F7uhp1zi5icwmsinbr5us.png" alt="Scrollbar container"&gt;&lt;/a&gt;Scrollbar container
  

&lt;/p&gt;

&lt;p&gt;It should be noted that this div is an hidden div i.e. &lt;code&gt;visibility: hidden&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can take a look at this &lt;code&gt;scrollbar-container&lt;/code&gt; in the codebase &lt;a href="https://github.com/keyurparalkar/render-million-rows/blob/0bd6442ba8e9a62c65f3fa50e387fdc282a5000b/src/App.tsx#L270" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the Drawing Mechanism
&lt;/h3&gt;

&lt;p&gt;Now we have come to the main part which is the drawing mechanism. Before we jump into this I would like to say that all the drawing onto the &lt;code&gt;target-canvas&lt;/code&gt; happens from the worker thread. Remember we talked about initializing a worker whenever the component mounts? This is the same worker we are talking about. You can find the worker being initialized in the codebase &lt;a href="https://github.com/keyurparalkar/render-million-rows/blob/0bd6442ba8e9a62c65f3fa50e387fdc282a5000b/src/App.tsx#L207" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The entire drawing mechanism a.k.a the worker code can be found &lt;a href="https://github.com/keyurparalkar/render-million-rows/blob/main/src/worker.ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So now we understand the it is the worker’s responsibility to draw the rows on the &lt;code&gt;target-canvas&lt;/code&gt; therefore let us dig into its mechanism.&lt;/p&gt;

&lt;p&gt;I would like to explain this mechanism with the help of three different approaches:&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 1
&lt;/h3&gt;

&lt;p&gt;In this approach, once the entire data is loaded onto the memory we directly draw it onto our &lt;code&gt;target-canvas&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fv1ablp4it0gx5o3hyckp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fv1ablp4it0gx5o3hyckp.png" alt="Approach 1"&gt;&lt;/a&gt;Approach 1
  

&lt;/p&gt;

&lt;p&gt;What will happen in this case? Any guesses? &lt;/p&gt;

&lt;p&gt;You guessed it right, all the 1M rows would get drawn onto the &lt;code&gt;target-canvas&lt;/code&gt; overwriting the previously drawn pixels and giving us the overwritten image like below:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2F8mc7j8fn2qjroi31kv58.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F8mc7j8fn2qjroi31kv58.png" alt="Approach 1"&gt;&lt;/a&gt;Approach 1
  

&lt;/p&gt;

&lt;p&gt;So as you can see the canvas is redrawn on itself leading to a distorted image. Hence this approach is bad and should not be taken.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 2
&lt;/h3&gt;

&lt;p&gt;In this approach, rather than drawing the entire data all at once, we draw a chunk of data onto the &lt;code&gt;target-canvas&lt;/code&gt;. We can take a chunk size to be equal to the number of rows that can fit on the canvas. &lt;/p&gt;

&lt;p&gt;Here is the visual representation of drawing a chunk on the canvas:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2F5y6mhtyzhbukplwqit7w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5y6mhtyzhbukplwqit7w.gif" alt="Approach 2"&gt;&lt;/a&gt;Approach 2
  

&lt;/p&gt;

&lt;p&gt;We do this as we scroll down the data and draw each chunk of rows. But there are certain things to consider before taking this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To draw a row you need to draw all the cells in it equivalent to the number of columns.&lt;/li&gt;
&lt;li&gt;Also, to draw each cell you need to:

&lt;ul&gt;
&lt;li&gt;First, clear the canvas with that cell area with clearRect.&lt;/li&gt;
&lt;li&gt;Then to draw the cell we use &lt;code&gt;[strokeRect](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeRect)&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;Lastly, to fill the data in it we make use of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillRect" rel="noopener noreferrer"&gt;fillRect&lt;/a&gt; function.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;All these steps happen for every cell that we draw, it is going to happen for every row and every chunk as you scroll down through the data.&lt;/li&gt;

&lt;li&gt;This is a very expensive operation.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;There is another approach that I used to achieve this without degrading the performance. Let us look into that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 3
&lt;/h3&gt;

&lt;p&gt;In this approach, we make use of the &lt;code&gt;offscreen canvas&lt;/code&gt; API. So the algorithm is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each offscreen canvas will consist of 100 rows draw onto them from the CSV data.&lt;/li&gt;
&lt;li&gt;These canvases are created based on the scroll position. So based on the &lt;code&gt;scrollTop&lt;/code&gt; position, we calculate the number of rows we have scrolled off.&lt;/li&gt;
&lt;li&gt;Based on this number we calculate the range of rows that we need to draw on the canvas. For example, if &lt;code&gt;scrollTop = 150&lt;/code&gt;, then we select rows from 100 to 200 and draw them onto the newly created offscreen canvas.&lt;/li&gt;
&lt;li&gt;We also generate another offscreen canvas, that draws the next set of 100 rows. From the above example, the next canvas will contain rows from 200 to 300.&lt;/li&gt;
&lt;li&gt;We store all these canvases during the scroll in a global state in the worker which you can take a look &lt;a href="https://github.com/keyurparalkar/render-million-rows/blob/0bd6442ba8e9a62c65f3fa50e387fdc282a5000b/src/worker.ts#L190" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Once the canvases are ready we simply take the chunk of the current offscreen canvas and draw it as an image onto the &lt;code&gt;target-canvas&lt;/code&gt;. Here the chunk size is the size equal to the number of rows that can fit inside the &lt;code&gt;target-canvas&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When I say we take a chunk from the current offscreen canvas by that I mean we copy the chunk from that offscreen canvas as an image and draw it onto the &lt;code&gt;target-canvas&lt;/code&gt; with the help of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage" rel="noopener noreferrer"&gt;drawImage&lt;/a&gt; function. This operation is called bliting. You can find more information about it &lt;a href="https://es.wikipedia.org/wiki/Bit_blit" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To understand this visually, here is a small animation that will make things clearer:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2F5f4oeen4640zabesu356.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5f4oeen4640zabesu356.gif" alt="Approach 3"&gt;&lt;/a&gt;Approach 3
  

&lt;/p&gt;

&lt;p&gt;The blue animation that you see here is the scenario where your scroll bar position intersects between the two offscreen canvases. For example, if you have completed drawing the entire 1st offscreen canvas on &lt;code&gt;target-canvas&lt;/code&gt; then for the remaining portion of the &lt;code&gt;target-canvas&lt;/code&gt; you will need to paint it with the exact number of rows in the next offscreen canvas. &lt;/p&gt;

&lt;p&gt;This creates an experience of continuous data visibility while scrolling thus giving consistent experience.&lt;/p&gt;

&lt;p&gt;So with this approach 3, you will be able to scroll normally with the mouse-wheel/touch-pad or while you are dragging the scroll bar to the bottom.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;So that’s it, folks. In this blog, we learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How an uncommon solution like drawing on canvas solves the most common problem.&lt;/li&gt;
&lt;li&gt;The mechanism of understanding the infinite scrolling container.&lt;/li&gt;
&lt;li&gt;We saw how the canvas is initialized.&lt;/li&gt;
&lt;li&gt;We also saw, the DOM structure of the component&lt;/li&gt;
&lt;li&gt;We saw how the component gets initialized and how the control gets transferred to the worker.&lt;/li&gt;
&lt;li&gt;Finally, we saw different approaches of drawing on the canvas when you are scrolling fast.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire codebase for this project can be found here: &lt;a href="https://github.com/keyurparalkar/render-million-rows" rel="noopener noreferrer"&gt;https://github.com/keyurparalkar/render-million-rows&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;Follow me on &lt;a href="https://twitter.com/keurplkar" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar" rel="noopener noreferrer"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/" rel="noopener noreferrer"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Recursive elements in React</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Mon, 04 Mar 2024 10:36:51 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/recursive-elements-in-react-3jp1</link>
      <guid>https://forem.com/keyurparalkar/recursive-elements-in-react-3jp1</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A couple of days back I was wondering how components like these are built:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fsrpavevu4wxm6xdqph8p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fsrpavevu4wxm6xdqph8p.gif" alt="intro-simple-tree.gif"&gt;&lt;/a&gt;Tree Component
  

&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fi62zwj7r256uef3wb5so.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fi62zwj7r256uef3wb5so.png" alt="intro-draw-component.png"&gt;&lt;/a&gt;JSON to HTML Elements
  

&lt;/p&gt;

&lt;p&gt;A common thing between these components is that there is a definitive pattern that gets repeated. For example, when you click on a title in the tree component, it expands. When you click on the inner title it expands and so on.&lt;/p&gt;

&lt;p&gt;In the world of programming, to deal with these kinds of repetitive patterns we either use loops or recursions.&lt;/p&gt;

&lt;p&gt;Everyone deals with them differently depending on their usecase. For this blogpost, I will use recursion to implement these components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;I would highly recommend going through the below topics before reading this blog post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript" rel="noopener noreferrer"&gt;Basics of Javascript&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;Basics of React&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://styled-components.com/docs/basics" rel="noopener noreferrer"&gt;styled-components&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements" rel="noopener noreferrer"&gt;CSS pseudo-elements&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Recursion?
&lt;/h2&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fm89rrurwpz1if9t6blgy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fm89rrurwpz1if9t6blgy.gif" alt="what-is-recursion-i-know-a-guy.gif"&gt;&lt;/a&gt;Saul's Magic
  

&lt;/p&gt;

&lt;p&gt;As Sual Goodmen said, ‘Let’s just say I know a guy, who knows a guy, who knows another guy’. Recursion is similar to what he is trying to say.&lt;/p&gt;

&lt;p&gt;From &lt;a href="https://en.wikipedia.org/wiki/Recursion_(computer_science)" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;,&lt;/p&gt;

&lt;p&gt;💡 &lt;em&gt;**Recursion&lt;/em&gt;&lt;em&gt; is a method of solving a &lt;a href="https://en.wikipedia.org/wiki/Computational_problem" rel="noopener noreferrer"&gt;computational problem&lt;/a&gt; where the solution depends on solutions to smaller instances of the same problem.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In laymen terms, a problem is divided into a subproblem and the solution of that is passed down to the next subproblem. This goes on till the base condition is met where base condition stops this drill down.&lt;/p&gt;

&lt;p&gt;Let us consider a classic example of finding a factorial of a number:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So, in this function, &lt;code&gt;n&lt;/code&gt; is just the number we're finding the factorial for. The function keeps calling itself with &lt;code&gt;n - 1&lt;/code&gt; until it hits &lt;code&gt;0&lt;/code&gt;. When it does, it just returns &lt;code&gt;1&lt;/code&gt;. This is what we call the base case of the recursion. The return value gets multiplied with the current &lt;code&gt;n&lt;/code&gt; and is sent back up to the previous stack frame (which is the last time we called the function with &lt;code&gt;n+1&lt;/code&gt;). This cycle keeps on going until we get back to the very first function call (the original &lt;code&gt;n&lt;/code&gt;), and bam! We get our final factorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is Recursion?
&lt;/h2&gt;

&lt;p&gt;There are a couple of advantages to using recursion that I have in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simplicity and Readability&lt;/li&gt;
&lt;li&gt;Reduced Redundancy&lt;/li&gt;
&lt;li&gt;Divide and Conquer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can read more about the advantages in this blog post: &lt;em&gt;&lt;a href="https://pages.cs.wisc.edu/~vernon/cs367/notes/6.RECURSION.html#iter" rel="noopener noreferrer"&gt;Recursion&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's talk about Recursive React Elements
&lt;/h2&gt;

&lt;p&gt;From the definition of recursion explained above we know that a recursive function needs a base condition that helps it to get out of the recursion state. Similar to this function, we will make use of this concept in react to create recursive elements.&lt;/p&gt;

&lt;p&gt;Here is a visual example of a recursive element:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fsrpavevu4wxm6xdqph8p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fsrpavevu4wxm6xdqph8p.gif" alt="intro-simple-tree.gif"&gt;&lt;/a&gt;Tree Component
  

&lt;/p&gt;

&lt;p&gt;This recursive tree is a component based on an object that has repetitive nested children. For example, the above tree component is based on the following JSON structure:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The component that you see above is a tree component. Let us recognize some key parameters in this component from the definition of recursion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Recursive state&lt;/strong&gt;: Here the recursive state is the name or fields that are getting repeated one key within another.&lt;/p&gt;

&lt;p&gt;As you can see this object has an &lt;code&gt;id&lt;/code&gt; &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;children&lt;/code&gt; properties. Again the children's property is an array of tree i.e. object with &lt;code&gt;id&lt;/code&gt; &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;children&lt;/code&gt; properties. And this goes on and on. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Base condition:&lt;/strong&gt; In this example, the base/end case is when there are no elements to print out.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will be building an interactive component that will help us to visualize this object in the form of a tree. So without further ado! let us get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the recursive element
&lt;/h2&gt;

&lt;p&gt;What we are trying to implement is a tree that is interactive like we saw in the above section:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We build this component out of the following tags:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ul&lt;/code&gt; - to wrap all the list children&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;li&lt;/code&gt; - to present each element in the list of children&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;details&lt;/code&gt; - to make each &lt;code&gt;li&lt;/code&gt; tag interactive. This will help it to open and close the &lt;code&gt;li&lt;/code&gt; tag.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;summary&lt;/code&gt; - This will help to give the heading to the &lt;code&gt;li&lt;/code&gt; tag.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;So the structure is like this: &lt;code&gt;ul&lt;/code&gt; wraps all &lt;code&gt;li&lt;/code&gt; and each &lt;code&gt;li&lt;/code&gt; has &lt;code&gt;details&lt;/code&gt; and &lt;code&gt;summary&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fhpv7myou8nru56byrvuf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fhpv7myou8nru56byrvuf.jpeg" alt="Representation of Tree with the above elements"&gt;&lt;/a&gt;Representation of Tree with the above elements
  

&lt;/p&gt;

&lt;p&gt;Let us call this component a &lt;code&gt;RecursiveTree&lt;/code&gt; and create the component file for the same. Paste the below code in it:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let me explain what’s going on here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We have a styled component: &lt;code&gt;StyledUnorderedList&lt;/code&gt; that has the following styles:&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;We loop over all the children's elements with the map function that wraps each item with the &lt;code&gt;CustomDetails&lt;/code&gt; component:&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;This &lt;code&gt;CustomDetails&lt;/code&gt; component looks like below:&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;The purpose of this component is to provide modified/additional functionalities apart from the existing &lt;code&gt;details&lt;/code&gt; HTML element. Here are the additional functionalities that it provides:

&lt;ul&gt;
&lt;li&gt;You can provide icons that can be rendered in front of each element in the tree.

&lt;ul&gt;
&lt;li&gt;For that, you need to provide an array of two icons. The first one is the open icon and the second is the close icon.&lt;/li&gt;
&lt;li&gt;It is to be noted that I made use of &lt;em&gt;&lt;a href="https://react-icons.github.io/react-icons/" rel="noopener noreferrer"&gt;react-icons&lt;/a&gt;&lt;/em&gt; icon library.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Interactive change of icon when the detail’s tag gets toggled.&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;The component above is pretty self-explanatory and you can get a jest of out of it by a glance.&lt;/li&gt;

&lt;li&gt;Let us test out this component. Render this component as below and see the output:&lt;/li&gt;

&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;

&lt;a href="https://media.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%2Feo0ybwah9hinl2qb49n3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Feo0ybwah9hinl2qb49n3.gif" alt="Tree with no custom icon field in the JSON object"&gt;&lt;/a&gt;Tree with no custom icon field in the JSON object
  

&lt;/p&gt;
    

&lt;ul&gt;
&lt;li&gt;You can also pass your desired icons in the tree config like below:&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;

&lt;a href="https://media.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%2Fx6c3lleww85ycjarysmo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fx6c3lleww85ycjarysmo.gif" alt="Tree with custom icon field in the JSON object"&gt;&lt;/a&gt;Tree with custom icon field in the JSON object
  

&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveat: Event bubbling
&lt;/h2&gt;

&lt;p&gt;One thing I struggled with during the implementation of this component was the toggle interaction that happened at deeper levels of the tree where getting bubble i.e. the toggle event was getting applied from the target element to all the parent elements that had event handlers that catch this toggle event.&lt;/p&gt;

&lt;p&gt;To avoid this scenario, I made use of the &lt;code&gt;e.stopPropogation&lt;/code&gt; function to stop the event from &lt;strong&gt;&lt;em&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling" rel="noopener noreferrer"&gt;bubbling&lt;/a&gt;.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To better explain the problem here are the visualized representations of the same:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fx6c3lleww85ycjarysmo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fx6c3lleww85ycjarysmo.gif" alt="No event bubbling"&gt;&lt;/a&gt;No event bubbling
  

&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fyme2ak7260vft3z8hwlo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fyme2ak7260vft3z8hwlo.gif" alt="With Event bubbling"&gt;&lt;/a&gt;With Event bubbling
  

&lt;/p&gt;

&lt;p&gt;It took me a small bit of time to understand the issue at hand but after careful debugging, I was able to resolve it. &lt;/p&gt;

&lt;p&gt;So to provide a better interactivity in the recursive elements make sure that the events don’t get bubbled up (if that’s the desired behaviour you want). &lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus Element!!
&lt;/h2&gt;

&lt;p&gt;So this was fun. So before closing up, I would also like to share another example. This example is of recursively adding components based on a JSON config. I will just place the code below along with its output for reference.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You get the following out: &lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2Fi62zwj7r256uef3wb5so.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fi62zwj7r256uef3wb5so.png" alt="intro-draw-component.png"&gt;&lt;/a&gt;JSON to HTML Elements
  

&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;To summarize, we learned a couple of things here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is recursion?&lt;/li&gt;
&lt;li&gt;What are recursive react elements?&lt;/li&gt;
&lt;li&gt;Building the RecursiveTree component&lt;/li&gt;
&lt;li&gt;Caveats&lt;/li&gt;
&lt;li&gt;Bonus Element&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire code for this tutorial can be found &lt;a href="https://github.com/keyurparalkar/recursive-component-examples" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;Follow me on &lt;a href="https://twitter.com/keurplkar" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar" rel="noopener noreferrer"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/" rel="noopener noreferrer"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>react</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How I build a YouTube Video Player with ReactJS: Add chapters to the video</title>
      <dc:creator>Keyur Paralkar</dc:creator>
      <pubDate>Wed, 21 Feb 2024 11:08:15 +0000</pubDate>
      <link>https://forem.com/keyurparalkar/how-i-build-a-youtube-video-player-with-reactjs-add-chapters-to-the-video-1nde</link>
      <guid>https://forem.com/keyurparalkar/how-i-build-a-youtube-video-player-with-reactjs-add-chapters-to-the-video-1nde</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you are into online learning/education or an unboxing video of a gadget on youtube, etc. Then I am pretty sure you might have come across this thing here:&lt;/p&gt;

&lt;p&gt;

&lt;a href="https://media.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%2F4gmtoavgn09uqcp9gjru.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F4gmtoavgn09uqcp9gjru.gif" alt="Youtube’s Video Frame Preview"&gt;&lt;/a&gt;Youtube’s progress bar gets split up into multiple mini sliders. &lt;a href="https://www.youtube.com/watch?v=TwDJhUJL-5o&amp;amp;t=356s" rel="noopener noreferrer"&gt;Video source&lt;/a&gt;
  

&lt;/p&gt;

&lt;p&gt;The progress bar is broken into sections and each section describes what it represents. This is mostly done by the video's author so that viewers can quickly get a gist of what they will be learning in this section or the next few minutes. &lt;/p&gt;

&lt;p&gt;These quick gist of each section are called chapters. In this article, we will be looking at how to implement them.&lt;/p&gt;

&lt;p&gt;So without further ado, let us get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What are VTTs? &lt;em&gt;&lt;a href="https://dev.to/keyurparalkar/how-i-build-a-youtube-video-player-with-reactjs-building-frametooltip-component-3o6p"&gt;My previous Blog post&lt;/a&gt;&lt;/em&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebVTT_API" rel="noopener noreferrer"&gt;&lt;em&gt;MDN&lt;/em&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Project Architecture: &lt;em&gt;Previous Post: &lt;a href="https://dev.to/keyurparalkar/how-i-build-a-youtube-video-player-with-reactjs-building-frametooltip-component-3o6p"&gt;In depth&lt;/a&gt; or you can read the &lt;a href="https://dev.to/keyurparalkar/building-with-react-js-create-your-own-youtube-video-player-starting-with-basics-1lpp"&gt;summary&lt;/a&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Slider component: Previous post: &lt;em&gt;&lt;a href="https://dev.to/keyurparalkar/how-i-build-a-youtube-video-player-with-reactjs-build-the-seekbar-control-3kg"&gt;How I build a YouTube Video Player with ReactJS: Build the Seekbar control&lt;/a&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Understanding of &lt;em&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track" rel="noopener noreferrer"&gt;track element&lt;/a&gt;&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Understanding of Javascript’s map function, editing element attributes.&lt;/li&gt;
&lt;li&gt;React: &lt;a href="https://react.dev/reference/react/useImperativeHandle" rel="noopener noreferrer"&gt;&lt;code&gt;useImperativeHandle&lt;/code&gt; hook&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The What?
&lt;/h2&gt;

&lt;p&gt;So this broken time bar/seek bar/ progress bar that you see on the video is nothing but chapters. This is a very common feature that you get to see on YouTube.  &lt;/p&gt;

&lt;p&gt;We already have built the seek bar in our previous blog posts and with some tweaks to the existing Slider component we can achieve this functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Why?
&lt;/h2&gt;

&lt;p&gt;We are building this component because it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tells the user what is happening in the given time frame.&lt;/li&gt;
&lt;li&gt;Gives a quick reference to the content the user is looking for with the help of chapter text below the frame snapshot.&lt;/li&gt;
&lt;li&gt;Provides a better User experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The How?
&lt;/h2&gt;

&lt;p&gt;Before we get started with the implementation let us have a quick overview of what the steps are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate VTT for chapters&lt;/li&gt;
&lt;li&gt;Load the VTT into the video with the help of &lt;code&gt;track&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;Extract chapters from the &lt;code&gt;track&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;Update the Slider component for the chapter logic&lt;/li&gt;
&lt;li&gt;Display the chapters in the tooltip&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There isn’t much jargon here if you have gone through the previous article. If not, I would highly recommend going through it from the prerequisites section.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;💡 &lt;strong&gt;NOTE:&lt;/strong&gt; The implementation of chapter fill css-variable was inspired from the &lt;a href="https://www.vidstack.io/" rel="noopener noreferrer"&gt;https://www.vidstack.io/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Generating VTT for chapters
&lt;/h2&gt;

&lt;p&gt;Web video text track is a file format that has time-based data. Meaning, that it contains text that needs to be shown on the video along with the information of when this text needs to be shown(nth second). &lt;/p&gt;

&lt;p&gt;Since we want the users to know from which second to which second the chapter starts and ends we will write a VTT file like the one below:&lt;/p&gt;

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

WEBVTT

00:00:00.000 --&amp;gt; 00:00:15.000
Chapter 1

00:00:15.000 --&amp;gt; 00:00:42.000
Chapter 2

00:00:42.000 --&amp;gt; 00:00:48.000
Chapter 3

00:00:48.000 --&amp;gt; 00:01:01.000
Chapter 4

00:01:01.000 --&amp;gt; 00:01:09.000
Chapter 5 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This tells us that, from the 0th to the 15th second there would be text that corresponds to Chapter 1 and so on.&lt;/p&gt;
&lt;h2&gt;
  
  
  Load the VTT into the video
&lt;/h2&gt;

&lt;p&gt;Next, to load the VTT into the video we make use of the &lt;code&gt;[track&lt;/code&gt; element.](&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track&lt;/a&gt;) We update the &lt;code&gt;Video.tsx&lt;/code&gt;  like below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Here we added a track element with kind attribute of chapters. In the src attribute make sure that you place the location/url of the chapter’s &lt;code&gt;vtt&lt;/code&gt; file that we generated above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extracting chapters from the &lt;code&gt;track&lt;/code&gt; element
&lt;/h2&gt;

&lt;p&gt;Now that we have &lt;code&gt;track&lt;/code&gt; element in place let us make use of it to extract the chapters into our code. What we want here is that we need these chapters when the video is loaded completely. &lt;/p&gt;

&lt;p&gt;To do that, we already have a &lt;code&gt;useEffect&lt;/code&gt; in the &lt;code&gt;Video.tsx&lt;/code&gt; file that hydrates the store with some parameters. We make use of this same effect to capture the chapters. Copy and paste below &lt;code&gt;useEffect&lt;/code&gt; :&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here we make use of the video element’s &lt;code&gt;loadeddata&lt;/code&gt; event to hydrate the store. The code is pretty self-explanatory but I would like to explain the part of the chapter here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In line 12, we make use of &lt;code&gt;trackChaptersRef&lt;/code&gt; which is being passed to the track element. From this, we access the &lt;code&gt;track&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;In line 13, we get all the cues in the track.&lt;/li&gt;
&lt;li&gt;On the next line, we make use of the &lt;code&gt;map&lt;/code&gt; function to return an array of objects that consists of:

&lt;ul&gt;
&lt;li&gt;index&lt;/li&gt;
&lt;li&gt;name of the chapter, start and end time&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;percentageTime&lt;/code&gt;: This represents what percentage of time this chapter contributes to out of the total video duration.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I know this hydration of chapter object with additional fields doesn’t make any sense right now but it will when we get into the changes of the slider component. We will discuss this in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update the Slider component for the chapter logic
&lt;/h2&gt;

&lt;p&gt;Folks, take a cup of coffee now since this will be a long section. I will try my best to make it interesting 🙂.&lt;/p&gt;

&lt;p&gt;Before proceeding further, I would highly recommend going through this &lt;a href="https://dev.to/keyurparalkar/how-i-build-a-youtube-video-player-with-reactjs-build-the-seekbar-control-3kg"&gt;Slider component implement article.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the outline of the steps that we will be doing to achieve the chapter functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Split the Slider component into multiple mini-slider components&lt;/li&gt;
&lt;li&gt;Handling Slider fill across the multiple mini-sliders&lt;/li&gt;
&lt;li&gt;Handling mouse moves on hover, click and drag.&lt;/li&gt;
&lt;li&gt;Updating the overall slider on playback&lt;/li&gt;
&lt;li&gt;Styling the slider&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Split the Slider component into multiple mini-slider components
&lt;/h3&gt;

&lt;p&gt;Ok so hear me out:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Chapters on Slider is nothing but a bunch of mini sliders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;From this what I mean is, in this functionality, we won’t have a single slider of width 100%. But instead, we will have mini sliders of length equal to the width of &lt;code&gt;percentageTime&lt;/code&gt;. This state is the derived state that we computed when we loaded the video component in the above section.&lt;/p&gt;

&lt;p&gt;We got the jest of what we are doing, now let us start with the implementation. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first thing that we need to do is, extend our Slider component such that it accepts chapters as a prop:

&lt;ul&gt;
&lt;li&gt;Let us update the &lt;code&gt;SliderProps&lt;/code&gt; interface:
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Update the render method of the slider component such that when chapters are enabled we map over them and create multiple sliders:
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;We also maintain references to all these mini sliders with the help of chapterRefs. It is an array ref that holds the reference to these elements. We do this in this line:
```
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;ref={(el: HTMLDivElement) =&amp;gt; el &amp;amp;&amp;amp; (chapterRefs.current[index] = el)}&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    - Quick thing to note here, We have created a StyleChapterContainer. It may look like this:
      &lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- It accepts a prop as `$width` that defines the width of this mini - slider component.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Now pass the chapters to the slider component via the seekbar component as follows:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once this is hooked the output will look like below&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fi5b19o40eoow9fahpqt2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fi5b19o40eoow9fahpqt2.png" alt="Chapters as mini sliders"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Handling filling logic on mouse move and click events
&lt;/h3&gt;

&lt;p&gt;The above logic needs to be handled for the following scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;While clicking and,&lt;/li&gt;
&lt;li&gt;While dragging the slider&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the pictorial representation of these scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;While Clicking:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;lt;p&amp;gt;&lt;br&gt;
&amp;lt;figure&amp;gt;&lt;br&gt;
&amp;lt;img src="&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/erymo9rbzpjls48q4cw5.gif" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/erymo9rbzpjls48q4cw5.gif&lt;/a&gt;" alt="Click interaction on sliders with chapters" /&amp;gt;&lt;br&gt;
  &amp;lt;figcaption&amp;gt;Click interaction on sliders with chapters&amp;lt;/figcaption&amp;gt;&lt;br&gt;
&amp;lt;/figure&amp;gt;&lt;br&gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;While dragging:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;lt;p&amp;gt;&lt;br&gt;
&amp;lt;figure&amp;gt;&lt;br&gt;
&amp;lt;img src="&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g8ryc9ia89pw6gc3bvo6.gif" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g8ryc9ia89pw6gc3bvo6.gif&lt;/a&gt;" alt="Drag interaction on sliders with chapters" /&amp;gt;&lt;br&gt;
  &amp;lt;figcaption&amp;gt;Drag interaction on sliders with chapters&amp;lt;/figcaption&amp;gt;&lt;br&gt;
&amp;lt;/figure&amp;gt;&lt;br&gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;aside&amp;gt;&lt;br&gt;
&lt;em&gt;💡 &lt;strong&gt;NOTE: I would like to remind you guys that to go through this blogpost: &lt;em&gt;&lt;a href="https://dev.to/keyurparalkar/how-i-build-a-youtube-video-player-with-reactjs-build-the-seekbar-control-3kg"&gt;How I build a YouTube Video Player with ReactJS: Build the Seekbar control&lt;/a&gt;&lt;/em&gt; before proceeding further. Because it contains a lot of jargon which is better explained there.&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
&amp;lt;/aside&amp;gt;&lt;/p&gt;

&lt;p&gt;So here we go, below is the &lt;code&gt;handleClick&lt;/code&gt; event handler that takes care of fill the chapters on click:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;Below is the explanation for the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This part right here calculates all the chapter's width and with the help of the current &lt;code&gt;--slider-fill&lt;/code&gt; value we get the current chapter index:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Next, we get the previous and the next chapter elements:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Next, we fill all the previous chapters before the current chapter:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A thing to note here, we track the fill of each slider element with the help of the CSS variable: &lt;code&gt;--chapter-fill&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We also need to update our &lt;code&gt;StyledSliderFill&lt;/code&gt; component such that whenever chapters exist we make use of the &lt;code&gt;—chapter-fill&lt;/code&gt; CSS variable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Next, we summon all the chapter fill values below:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;Then, to fill the current chapter we make use of the &lt;code&gt;computeCurrentWidthFromPointerPos&lt;/code&gt; utility function and then finally set its value to the current chapter’s &lt;code&gt;--chapter-fill&lt;/code&gt;.&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;For scenarios of clicking from right to left direction i.e. going back in video, we fill the next chapter to 0 from the current chapter:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;Similarly, we make use of the &lt;code&gt;handleMouseMove&lt;/code&gt; function that handles the filling of chapters during the &lt;code&gt;mousemove&lt;/code&gt; event i.e. when we are dragging the slider knob:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;This is the same function we used to update the &lt;code&gt;--slider-pointer&lt;/code&gt; CSS variable in the previous blog posts. The purpose of this function from the chapters point of view is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update the chapter fill of the respective elements&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;data-chapter-dragging&lt;/code&gt; attribute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would like you guys to go through the comments in the above code block to understand the functionality. &lt;/p&gt;

&lt;p&gt;Just a quick note: The purpose of adding &lt;code&gt;data-chapter-dragging&lt;/code&gt; attribute is to use it in styling which we will look into in the later section.&lt;/p&gt;
&lt;h3&gt;
  
  
  Updating the slider position on playback
&lt;/h3&gt;

&lt;p&gt;There is one more scenario left that we need to cover which is handling the playback mechanism across multiple sliders. Now to do this we need a mechanism that will help us to update the &lt;code&gt;--chapter-fill&lt;/code&gt; CSS variable of each chapter whenever the current duration of the video changes.&lt;/p&gt;

&lt;p&gt;This is a simple task. We just need to expose a function that updates this chapter fill for the given chapter with the help of &lt;code&gt;[useImperativeHandle&lt;/code&gt; hook](&lt;a href="https://react.dev/reference/react/useImperativeHandle" rel="noopener noreferrer"&gt;https://react.dev/reference/react/useImperativeHandle&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The first thing is to update the &lt;code&gt;useImperativeHandle&lt;/code&gt; hook in the &lt;code&gt;Slider&lt;/code&gt; component:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;We introduced a new function here: &lt;code&gt;updateChapterFill&lt;/code&gt; which accepts the current chapter’s index and the percentage completion of that chapter. &lt;/p&gt;

&lt;p&gt;Next, we consume this function via refs in the &lt;code&gt;Seekbar&lt;/code&gt; component like below:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;Inside the &lt;code&gt;Seekbar&lt;/code&gt; component, we access the &lt;code&gt;currentTime&lt;/code&gt; and the &lt;code&gt;chapters&lt;/code&gt; from the player context. &lt;/p&gt;

&lt;p&gt;Then we make use of the &lt;code&gt;useEffect&lt;/code&gt; that updates on &lt;code&gt;currentTime&lt;/code&gt; and &lt;code&gt;isSeeking&lt;/code&gt;. Along with updating the &lt;code&gt;slider-fill&lt;/code&gt; it also updates the chapter fill with the help of &lt;code&gt;updateChapterFill&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We do some simple calculations and get the &lt;code&gt;currentChapterFillWidth&lt;/code&gt; by dividing the &lt;code&gt;currentTime&lt;/code&gt; by the total chapter duration. &lt;/p&gt;

&lt;p&gt;lastly, we pass this to our update function.&lt;/p&gt;

&lt;p&gt;This is how our functionality will look like when during playback:&lt;/p&gt;

&lt;p&gt;&amp;lt;p&amp;gt;&lt;br&gt;
&amp;lt;figure&amp;gt;&lt;br&gt;
&amp;lt;img src="&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/whuawmq3nm8u8ucmy6nd.gif" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/whuawmq3nm8u8ucmy6nd.gif&lt;/a&gt;" alt="Chapter fill on video playback" /&amp;gt;&lt;br&gt;
  &amp;lt;figcaption&amp;gt;Chapter fill on video playback&amp;lt;/figcaption&amp;gt;&lt;br&gt;
&amp;lt;/figure&amp;gt;&lt;br&gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Styling the chapter sliders
&lt;/h3&gt;

&lt;p&gt;One last thing that is pending is adding a small styling effect that will give better UX feedback. The style that I am talking about is increasing the width of the slider whenever we are dragging the slider like below:&lt;/p&gt;

&lt;p&gt;&amp;lt;p&amp;gt;&lt;br&gt;
&amp;lt;figure&amp;gt;&lt;br&gt;
&amp;lt;img src="&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iyb08j2kbzjpj4tt56qy.gif" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iyb08j2kbzjpj4tt56qy.gif&lt;/a&gt;" alt="Emphasising chapters on drag" /&amp;gt;&lt;br&gt;
  &amp;lt;figcaption&amp;gt;Emphasising chapters on drag&amp;lt;/figcaption&amp;gt;&lt;br&gt;
&amp;lt;/figure&amp;gt;&lt;br&gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;

&lt;p&gt;To do this we make use of the &lt;code&gt;data-chapter-dragging&lt;/code&gt; attribute that we add in the &lt;code&gt;handleMouseMove&lt;/code&gt; function. We use this attribute in &lt;code&gt;StyledContainer&lt;/code&gt; of the &lt;code&gt;Slider&lt;/code&gt; component:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;We make sure that whenever we are dragging i.e. whenever the container has the &lt;code&gt;data-dragging&lt;/code&gt; attribute only then check for any child div that has &lt;code&gt;data-chapter-dragging&lt;/code&gt; attribute. If it has then we update the height of the slider/container by &lt;code&gt;8px&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;So to summarize we achieved the following things in this blogpost:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We understand the reason why are we doing this feature.&lt;/li&gt;
&lt;li&gt;We saw how to get the chapter's data into the video via the track element.&lt;/li&gt;
&lt;li&gt;And lastly, we saw the changes that we need to make to the slider component to achieve the desired chapter UX.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire code for this tutorial can be found &lt;a href="https://github.com/keyurparalkar/react-youtube-player-clone" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;Follow me on &lt;a href="https://twitter.com/keurplkar" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="http://github.com/keyurparalkar" rel="noopener noreferrer"&gt;github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/keyur-paralkar-494415107/" rel="noopener noreferrer"&gt;linkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
