<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alex Regan</title>
    <description>The latest articles on DEV Community by Alex Regan (@alexsasharegan).</description>
    <link>https://dev.to/alexsasharegan</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%2F93170%2Fa3619812-995a-427a-b39e-ff904087696f.jpg</url>
      <title>DEV Community: Alex Regan</title>
      <link>https://dev.to/alexsasharegan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexsasharegan"/>
    <language>en</language>
    <item>
      <title>Build An Intersection Observer Directive In Vue</title>
      <dc:creator>Alex Regan</dc:creator>
      <pubDate>Thu, 06 Jun 2019 13:56:42 +0000</pubDate>
      <link>https://dev.to/alexsasharegan/build-an-intersection-observer-directive-in-vue-ljh</link>
      <guid>https://dev.to/alexsasharegan/build-an-intersection-observer-directive-in-vue-ljh</guid>
      <description>&lt;p&gt;In this post, I want to share my experience integrating the &lt;code&gt;IntersectionObserver&lt;/code&gt; API into a Vue app. By the end, we'll have a custom directive that abstracts dynamically registering and unregistering DOM elements with an observer.&lt;/p&gt;

&lt;h1&gt;
  
  
  Intersection Observer
&lt;/h1&gt;

&lt;p&gt;When you need to track an element coming into view, watching document scroll and calculating element offsets used to be the only way. The math isn't particularly complex, but knowing which layout properties to use and just how to calculate position relative to the right elements is a painful task. In addition, since &lt;code&gt;scroll&lt;/code&gt; fires a large amount of events very rapidly, it's easy to cause jank if your calculations and subsequent processing exceeds the frame budget--most likely because too many events are being processed within a single frame.&lt;/p&gt;

&lt;p&gt;Enter the &lt;code&gt;IntersectionObserver&lt;/code&gt;. Aptly named, an instance of &lt;code&gt;IntersectionObserver&lt;/code&gt; can observe many elements and invoke a callback when elements intersect or stop intersecting with the viewport or another element &lt;em&gt;(usually some scrollable container)&lt;/em&gt;. The built-in class is able to efficiently calculate intersection, and it does so with much simpler code &lt;em&gt;(no math!)&lt;/em&gt;. On top of this nice abstraction, &lt;code&gt;IntersectionObserver&lt;/code&gt; also handles scenarios that are often forgotten &lt;em&gt;(like &lt;code&gt;resize&lt;/code&gt; events)&lt;/em&gt; as well as extra difficult scenarios &lt;em&gt;(like &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; elements)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Before we start integrating this API into Vue, here are resources for more background on Vue directives and &lt;code&gt;IntersectionObserver&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vuejs.org/v2/guide/custom-directive.html"&gt;Vue Custom Directives&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/web/updates/2016/04/intersectionobserver"&gt;IntersectionObserver's Coming Into View by Surma&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API"&gt;MDN Intersection Observer API Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver"&gt;MDN IntersectionObserver Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;p&gt;One of the first challenges of using &lt;code&gt;IntersectionObserver&lt;/code&gt; in Vue is that our component's DOM is an artifact of our template and state. Declarative, component UI aims to keep us away from the DOM, but working with our observer requires plugging it into our real elements, not our template. This means we have to get our hands dirty, dig into our components raw elements, and be wary of the component lifecycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick And Dirty
&lt;/h2&gt;

&lt;p&gt;First things first: let's just prototype something and make it work. I'm going to start with a codesandbox vue project, and replace the &lt;code&gt;App.vue&lt;/code&gt; component with a big list of items to overflow the viewport. With some scrollable dummy content, we can task ourselves with detecting when an item comes in/out of view.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make A Big List
&lt;/h3&gt;

&lt;p&gt;Let's start by making our overflowing list. To create a list of dummy elements, we'll use a computed property called &lt;code&gt;range&lt;/code&gt;. This property doesn't use any fields from the component instance, so it's effectively a constant. The shortest way to create a range-like array of numbers &lt;code&gt;1-100&lt;/code&gt; is to use a trick based on iterables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;range&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="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="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;Array.from&lt;/code&gt; accepts any iterable as it's first parameter, and then an optional mapping function to transform each item yielded from the iterable. In what feels like a total cheat, we create a 100 item iterable by simply creating an object with a numeric length property: &lt;code&gt;{ length: 100 }&lt;/code&gt;. Our transform skips the values yielded from our iterable &lt;em&gt;(since they are void)&lt;/em&gt; and instead returns the index plus 1. You can imagine the internals of &lt;code&gt;Array.from&lt;/code&gt; starting up an old fashioned for loop and calling our transform function on each iteration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The default transform just returns whatever is yielded from the iterable.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;identity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iterable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;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;iterable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iterable&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="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;list&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;To render the list, we can use a &lt;code&gt;v-for&lt;/code&gt; directive. We'll place a data attribute referencing our id so later we can reference the element from the intersection observer's callback. We'll also place a ref here so we can pass these elements to our observer to be observed. Placing a ref on an element with &lt;code&gt;v-for&lt;/code&gt; will give us an array of elements at &lt;code&gt;vm.$refs.items&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"items"&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"i in range"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"i"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt; &lt;span class="na"&gt;:data-id=&lt;/span&gt;&lt;span class="s"&gt;"i"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Item Number #{{i}}
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Managing State
&lt;/h3&gt;

&lt;p&gt;Now we need to figure out how to store which items are in view. We could fill an array with ids that are in view, but when reacting to changes from the observer, we would have to filter the list on each entry that is not intersecting, and push each entry that is intersecting. That makes additions cheap, but deletions potentially expensive.&lt;/p&gt;

&lt;p&gt;To improve the performance implications of the array we could use a set. The &lt;code&gt;Set#has&lt;/code&gt;, &lt;code&gt;Set#add&lt;/code&gt; and &lt;code&gt;Set#delete&lt;/code&gt; methods would make it fast and easy to remove items leaving view and add items entering view. The problem with a set is that Vue 2.x cannot observe its changes. We'll have to wait for Vue 3.x to leverage &lt;code&gt;Set&lt;/code&gt; and other newer built-ins.&lt;/p&gt;

&lt;p&gt;We can use an object to store the which ids are in view by using the id as the key and a boolean as the value--&lt;code&gt;true&lt;/code&gt; indicating it is in view, &lt;code&gt;false&lt;/code&gt; or no key present indicating out of view. This makes adding items as simple as adding a new property with a value of &lt;code&gt;true&lt;/code&gt;, and removing items can be excluded from the object or simply toggled to &lt;code&gt;false&lt;/code&gt;. This has one caveat: Vue cannot observe changes to new or deleted properties. We'll have to be careful to either use &lt;code&gt;Vue.set&lt;/code&gt; or replace our object with a new one so Vue will trigger its reactivity system to observe the new object with additional properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Record&amp;lt;string, boolean&amp;gt;&lt;/span&gt;
      &lt;span class="na"&gt;inViewById&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In addition to the reactivity caveats, we'll need to take into account the fact that our numeric ids will be cast to strings when used as object keys. This will just be for a ticker display of the items currently in view. We will want to sort entries so we aren't looking at a confusing jumble of item ids.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;inView&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inViewById&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isInView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pluckId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sortAtoi&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;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Destructure the Object Entry of key, value (dropping the key)&lt;/span&gt;
    &lt;span class="nx"&gt;isInView&lt;/span&gt;&lt;span class="p"&gt;([,&lt;/span&gt; &lt;span class="nx"&gt;inView&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;inView&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;pluckId&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="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="c1"&gt;// Sort ascii to int (a to i) is a sort function&lt;/span&gt;
    &lt;span class="c1"&gt;// that properly sorts numbers when passed as strings.&lt;/span&gt;
    &lt;span class="nx"&gt;sortAtoi&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&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="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Create The Observer
&lt;/h3&gt;

&lt;p&gt;Finally, we can instantiate an &lt;code&gt;IntersectionObserver&lt;/code&gt;. We could do this in our component &lt;code&gt;data&lt;/code&gt;, but we don't need it to be reactive, and I'm not even sure how much of the observer's properties are Vue can make reactive. We could use the &lt;code&gt;created&lt;/code&gt; lifecycle hook, but our component DOM won't be accessible. We'll use the &lt;code&gt;mounted&lt;/code&gt; lifecycle hook so we have everything at our fingertips and also because that hook is not run in SSR contexts.&lt;/p&gt;

&lt;p&gt;We'll instantiate the &lt;code&gt;IntersectionObserver&lt;/code&gt;, which accepts a callback to handle changes on its observed elements. We'll set that up as a method we'll create next. We could also pass an object of options as the second parameter, but let's just go with the defaults for now.&lt;/p&gt;

&lt;p&gt;After creating the observer, we'll iterate through our list of elements using the ref placed on the &lt;code&gt;v-for&lt;/code&gt;. We tell our new observer to observe each element, and then we'll save a handle to our observer so we can disconnect it and release it's resources before our component is destroyed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleIntersection&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;el&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$refs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;beforeDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disconnect&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;So here's where it gets a little interesting. Our observer callback is invoked with an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry"&gt;array of &lt;code&gt;IntersectionObserverEntry&lt;/code&gt; objects&lt;/a&gt; and a reference to our observer &lt;em&gt;(which we have saved on our component instance)&lt;/em&gt;. We're going to get one entry for each element we observed--so every element in our list. We can iterate through this list and use the entry's &lt;code&gt;isIntersecting&lt;/code&gt; property to determine whether or not it's in view.&lt;/p&gt;

&lt;p&gt;The interesting part is managing our state since we have to give Vue fresh objects if we want to add or remove properties from our map of what is in view. Here we've created a method to clone our map, but only adding items to the map if they're in view. We can keep the object smaller this way which benefits our clone process as well as our sorted list of ids in view.&lt;/p&gt;

&lt;p&gt;Once we have a fresh map of what is in view, we can iterate the entries and sync up visibility with our state. If an item is intersecting, we set that id to &lt;code&gt;true&lt;/code&gt;. If it's not intersecting, we need to check if it's visible in the old map and set it to &lt;code&gt;false&lt;/code&gt;. Those will be the items leaving view. By only setting it to &lt;code&gt;false&lt;/code&gt; when &lt;code&gt;true&lt;/code&gt;, we continue to preserve the smallest size map we can.&lt;/p&gt;

&lt;p&gt;The last thing to do is to assign the new map on our component instance. This will trigger Vue to observe the new object, detect changes and re-render.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;handleIntersection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;inViewById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloneInViewById&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;entry&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// You could check if this was not already true&lt;/span&gt;
          &lt;span class="c1"&gt;// to determine the item just came into view.&lt;/span&gt;
          &lt;span class="nx"&gt;inViewById&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inViewById&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="c1"&gt;// Leaving view.&lt;/span&gt;
          &lt;span class="nx"&gt;inViewById&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inViewById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inViewById&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;cloneInViewById&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;inViewById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="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;inView&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inViewById&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;inViewById&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="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;inViewById&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;h2&gt;
  
  
  Quick And Dirty Result
&lt;/h2&gt;

&lt;p&gt;Now to see the code in action! I've built the codesandbox using our snippets. Our component is correctly tracking which items are visible on screen and updating our ticker. This means we set up the observer properly and that we're managing our state in a Vue 2.x friendly way.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/lo7yz"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Problems
&lt;/h3&gt;

&lt;p&gt;Now that we have a working implementation, what are we missing?&lt;/p&gt;

&lt;p&gt;Our example shows a static list of elements, but what happens if we have a&lt;br&gt;
dynamic list? Items may be added or removed by user interaction, but our observer will still be watching the original set of items. What happens if we render an empty list when the component is loaded, then we get supplied a long list from a data fetch? Our observer will sit idle and not observe anything.&lt;/p&gt;

&lt;p&gt;What if we want to use an observer passed as a prop from a parent component? We'll need to be reactive to that observer changing. We might also need to be prepared for not being given an observer at first, or the observer disappearing during the component's lifecycle.&lt;/p&gt;
&lt;h1&gt;
  
  
  Observe Directive
&lt;/h1&gt;

&lt;p&gt;What we need is a way to hook into the lower level Vue mechanics of when elements are added and removed from a component's DOM. Thankfully there's a way to do this, and it's a first-class Vue API: custom directives.&lt;/p&gt;
&lt;h2&gt;
  
  
  Refactor To Directive
&lt;/h2&gt;

&lt;p&gt;Now we need to see what we should extract from our prototype and into a directive. Our directive won't have any control over the observer except that it will be given as a directive prop. We're going to want to cover use cases for element insertion, update, and directive unbind. Using the directive should be a one-line change to pass our observer to our directive. Here it is in the context of our big list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt;
      &lt;span class="na"&gt;v-observe=&lt;/span&gt;&lt;span class="s"&gt;"observer"&lt;/span&gt;
      &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"items"&lt;/span&gt;
      &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"i in range"&lt;/span&gt;
      &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"i"&lt;/span&gt;
      &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;
      &lt;span class="na"&gt;:data-id=&lt;/span&gt;&lt;span class="s"&gt;"i"&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Item Number #{{i}}
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Insertion
&lt;/h4&gt;

&lt;p&gt;When an element is inserted, if we are given an observer, register the element with the observer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Update: Not Observed
&lt;/h4&gt;

&lt;p&gt;If we are given an observer, register the element with observer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Update: Already Observed
&lt;/h4&gt;

&lt;p&gt;If we are given an observer, check to see if it's the same observer. If it's different, attempt to unregister with the old observer and register with the new observer. It it's the same observer, do nothing.&lt;/p&gt;

&lt;p&gt;If we aren't given an observer, attempt to unregister with the old  observer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Directive Unbind
&lt;/h4&gt;

&lt;p&gt;If we are being observed, attempt to unregister with the old observer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;As you can see, there are a painful amount of use cases to support for a seamless abstraction. After listing the requirements, I can see that we are going to need to cache two pieces of state: the observer and whether or not we are currently being observed. We can use the observer's existence to derive whether or not we are being observed, but I find adding a data attribute makes it easier to peek in and see if things are working or not.&lt;/p&gt;

&lt;p&gt;To track state, we'll cache the observer directly on the element. To ensure we don't conflict with any DOM properties both present and future, we can create a local symbol that will give us exclusive access to our cached observer. We'll make the data attribute appear in the DOM as &lt;code&gt;data-v-observed="yes|no"&lt;/code&gt; by using the element's dataset in camelcase: &lt;code&gt;element.dataset.vObserved = "yes|no"&lt;/code&gt; &lt;em&gt;(read the pipe character as an "or")&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;What follows is a full directive implementation that seems too tedious to go through line-by-line. The &lt;code&gt;insert&lt;/code&gt; and &lt;code&gt;unbind&lt;/code&gt; cases are relatively easy to follow, but &lt;code&gt;update&lt;/code&gt; is tricky. I've done my best to reduce the complexity of the many possible cases by leveraging early returns and using names that hopefully make things more readable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kObserver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;v-observe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;markObserved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vObserved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;yes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;markNotObserved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vObserved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;cacheObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;kObserver&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;removeCachedObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;kObserver&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;inserted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&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="nx"&gt;observer&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;markObserved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;cacheObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;markNotObserved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;removeCachedObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&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;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&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="nx"&gt;observer&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;kObserver&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;sameObserver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;cached&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;observed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vObserved&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;yes&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;givenObserver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;observed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;givenObserver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;markObserved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;cacheObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;givenObserver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;markNotObserved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&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;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unobserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;removeCachedObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sameObserver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unobserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;markObserved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cacheObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="nx"&gt;unbind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;kObserver&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;cached&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unobserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;markNotObserved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;removeCachedObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&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;h2&gt;
  
  
  Final Result
&lt;/h2&gt;

&lt;p&gt;And here you have it--our prototype converted to use our custom &lt;code&gt;v-observe&lt;/code&gt; directive! She still works as before, but now you should be able to hot swap items in the list as well as change out intersection observers.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/5zq4p"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
    </item>
    <item>
      <title>Idle Map</title>
      <dc:creator>Alex Regan</dc:creator>
      <pubDate>Mon, 03 Jun 2019 15:26:32 +0000</pubDate>
      <link>https://dev.to/alexsasharegan/idle-map-cl</link>
      <guid>https://dev.to/alexsasharegan/idle-map-cl</guid>
      <description>&lt;p&gt;When you have code to run that's async, you have a few options. You can work with a &lt;code&gt;Promise&lt;/code&gt;, schedule something to run at a later time with &lt;code&gt;setTimeout&lt;/code&gt;, or schedule in coordination with the browser's render cycle via &lt;code&gt;requestAnimationFrame&lt;/code&gt;. Each has its own strength, but now there's a new tool in our async toolkit: &lt;code&gt;requestIdleCallback&lt;/code&gt;. I want to show off a trick to mix up promise-based tasks against the new &lt;code&gt;requestIdleCallback&lt;/code&gt; API (we'll just call it &lt;code&gt;rIC&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;If you want a primer on &lt;code&gt;rIC&lt;/code&gt;, check out the &lt;a href="https://developers.google.com/web/updates/2015/08/using-requestidlecallback"&gt;Google article&lt;/a&gt; from &lt;a href="https://developers.google.com/web/resources/contributors/paullewis"&gt;Paul Lewis&lt;/a&gt;. You can also get the full API rundown on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback"&gt;MDN&lt;/a&gt; as well as browser support information from &lt;a href="https://caniuse.com/#feat=requestidlecallback"&gt;caniuse&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea is to run a list of items through a processing function--essentially like &lt;code&gt;Array#map&lt;/code&gt;--except we want to ensure we intermittently yield control back to the main thread to remain responsive for user events. We can use &lt;code&gt;rIC&lt;/code&gt; to schedule each item's processing and check the &lt;code&gt;IdleDeadline&lt;/code&gt; to see if there is more time to process another item. If not, we can schedule another idle callback. We'll continue this process until every item in the list has been processed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;idleMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iterable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;processCallback&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="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&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;let&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;]();&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;processList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idleDeadline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;do&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;iterResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iterResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&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;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;processCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iterResult&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="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;idleDeadline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;didTimeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;requestIdleCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;processList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;requestIdleCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;processList&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 function, &lt;code&gt;idleMap&lt;/code&gt; takes your list (&lt;code&gt;iterable&lt;/code&gt;) and a callback (&lt;code&gt;processCallback&lt;/code&gt;), and it applies the callback to every item in the list just like &lt;code&gt;Array#map&lt;/code&gt;. Internally, it uses recursion by defining a closure (&lt;code&gt;processList&lt;/code&gt;) that it first schedules with an idle callback. Once that function is invoked by the browser, it uses the iterator to pull out items from the list and applies the processing callback on them. After each item, the &lt;code&gt;do..while&lt;/code&gt; control will evaluate whether or not the idle deadline has expired. If it hasn't, the function is free to process another item. If the deadline has expired, the &lt;code&gt;do..while&lt;/code&gt; control breaks and schedules another idle callback to continue processing the list. Once the list iterator has been consumed, the promise returned from &lt;code&gt;idleMap&lt;/code&gt; resolves with the results of each item's processing.&lt;/p&gt;

&lt;p&gt;I find that using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols"&gt;iterator interface&lt;/a&gt; works well with the &lt;code&gt;do..while&lt;/code&gt; control flow by removing the need to managing array indexes. As a major bonus, it also means we can map anything that satisfies the iterable interface. This could be doubly useful since it would allow the use of generator functions, custom objects, and various other non-array types to supply the items to be processed.&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>Wrapping Errors</title>
      <dc:creator>Alex Regan</dc:creator>
      <pubDate>Thu, 14 Feb 2019 15:55:34 +0000</pubDate>
      <link>https://dev.to/alexsasharegan/wrapping-errors-38hp</link>
      <guid>https://dev.to/alexsasharegan/wrapping-errors-38hp</guid>
      <description>&lt;p&gt;When performing I/O in Node.js servers, there is a lot of error handling to deal&lt;br&gt;
with. I always look to add as much context to errors as I can because it greatly&lt;br&gt;
reduces the time it takes me to find, understand, and fix bugs.&lt;/p&gt;

&lt;p&gt;We won't go into an error propagation strategy here &lt;em&gt;(that will be part of some&lt;br&gt;
of the upcoming material)&lt;/em&gt;, but I wanted to share a quick idea for how to&lt;br&gt;
decorate errors with context as they propagate through the stack.&lt;/p&gt;
&lt;h2&gt;
  
  
  Native Error
&lt;/h2&gt;

&lt;p&gt;JavaScript comes with a few built-in error classes. They include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Error&lt;/code&gt;: a base class for exceptions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EvalError&lt;/code&gt;: an error regarding the global &lt;code&gt;eval()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;InternalError&lt;/code&gt;: an error that occurred internally in the JavaScript engine.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RangeError&lt;/code&gt;: an error when a value is not in the set or range of allowed
values.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ReferenceError&lt;/code&gt;: an error when a non-existent variable is referenced.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SyntaxError&lt;/code&gt;: an error when trying to interpret syntactically invalid code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TypeError&lt;/code&gt;: an error when a value is not of the expected type.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;URIError&lt;/code&gt;: an error when a global URI handling function was used in a wrong
way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While we may sometimes find usages for specific built-ins like the &lt;code&gt;RangeError&lt;/code&gt;,&lt;br&gt;
most user-defined exceptions make use of the base &lt;code&gt;Error&lt;/code&gt; class. Its properties&lt;br&gt;
include a &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;, and &lt;code&gt;stack&lt;/code&gt;. In Node.js, error instances&lt;br&gt;
additionally contain a &lt;code&gt;code&lt;/code&gt; which identifies various error types including&lt;br&gt;
underlying system errors.&lt;/p&gt;

&lt;p&gt;Creating our own error &lt;em&gt;(and throwing it)&lt;/em&gt; looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;parseIntStrict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numLike&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numLike&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isInteger&lt;/span&gt;&lt;span class="p"&gt;(&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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`unable to parse input as integer: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;numLike&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="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we create and throw an error when &lt;code&gt;parseInt&lt;/code&gt; returns &lt;code&gt;NaN&lt;/code&gt; values. The&lt;br&gt;
message in the error is about as specific as we can make it without more&lt;br&gt;
context. This function might be called to convert user input for updating a&lt;br&gt;
product quantity in a shopping cart, parsing a field from a csv file, etc.--we&lt;br&gt;
can't know how it will be used.&lt;/p&gt;
&lt;h3&gt;
  
  
  In Context
&lt;/h3&gt;

&lt;p&gt;Let's say we are writing an api that takes a csv file and parses inventory&lt;br&gt;
quantities from its row fields. We're going to use our &lt;code&gt;parseIntStrict&lt;/code&gt; function&lt;br&gt;
when we parse a product's inventory count in the file. We might think of our api&lt;br&gt;
call stack like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[4]&lt;/code&gt; Parse quantity field&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[3]&lt;/code&gt; Parse csv row&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[2]&lt;/code&gt; Read file by lines&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[1]&lt;/code&gt; Map request to csv file on disk&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[0]&lt;/code&gt; Receive network request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a number of steps here before we use the &lt;code&gt;parseIntStrict&lt;/code&gt; function.&lt;br&gt;
Ideally, if a call to our function fails, we would like to know our request id,&lt;br&gt;
the name of the csv file on disk, the row index, and the field that caused the&lt;br&gt;
failure. If we have all that information, we can go straight to solving any&lt;br&gt;
broken functionality instead of exhausting valuable time diagnosing the source&lt;br&gt;
of the problem.&lt;/p&gt;
&lt;h2&gt;
  
  
  Wrapping Errors
&lt;/h2&gt;

&lt;p&gt;In order to achieve our goal of adding context to an error, we need a way to&lt;br&gt;
decorate errors and then bubble them back up the stack. One way we could do this&lt;br&gt;
is by adding a message representing the current context. We don't want our&lt;br&gt;
message to corrupt the original message in any way. This discourages us from&lt;br&gt;
attempting to manipulate the original error's message, but since we aren't&lt;br&gt;
always guaranteed error producers use the &lt;code&gt;Error&lt;/code&gt; class to generate exceptions,&lt;br&gt;
this isn't an option in the first place.&lt;/p&gt;

&lt;p&gt;Let's extend the &lt;code&gt;Error&lt;/code&gt; class so we can add a reference to the untouched,&lt;br&gt;
original error value. This will let us add our contextual message and keep a&lt;br&gt;
reference to the original error value regardless of it being an &lt;code&gt;Error&lt;/code&gt; instance&lt;br&gt;
or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;WrappedError&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="cm"&gt;/* context */&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;previous&lt;/span&gt; &lt;span class="cm"&gt;/* original error value */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// First we have to call the Error constructor with its expected arguments.&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// We update the error's name to distinguish it from the base Error.&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;constructor&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="c1"&gt;// We add our reference to the original error value (if provided).&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;previous&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;We aren't changing much from the base &lt;code&gt;Error&lt;/code&gt; class. We'll get the default&lt;br&gt;
&lt;code&gt;Error&lt;/code&gt; behaviors for free since we inherit &lt;em&gt;(generating stack traces,&lt;br&gt;
stringification, etc.)&lt;/em&gt;, but now our error type can reference a previous error.&lt;br&gt;
If we use a &lt;code&gt;WrappedError&lt;/code&gt; to generate our first exception, the previous error&lt;br&gt;
will be &lt;code&gt;undefined&lt;/code&gt;. If we create an instance passing in an &lt;code&gt;Error&lt;/code&gt; or a literal&lt;br&gt;
value, &lt;code&gt;previous&lt;/code&gt; will maintain a reference to it. Most interestingly, if we&lt;br&gt;
create an instance passing in another &lt;code&gt;WrappedError&lt;/code&gt; instance, we connect a&lt;br&gt;
chain of errors together.&lt;/p&gt;

&lt;p&gt;When we start using our &lt;code&gt;WrappedError&lt;/code&gt; throughout our application code, we&lt;br&gt;
essentially transform our error values to linked lists. The list head would be&lt;br&gt;
our current error's position in the stack, or its &lt;strong&gt;context&lt;/strong&gt;. We could traverse&lt;br&gt;
the list by checking for the existence of a previous error, and if it exists,&lt;br&gt;
checking to see if it's an instance of &lt;code&gt;WrappedError&lt;/code&gt;, which guarantees us a&lt;br&gt;
&lt;code&gt;previous&lt;/code&gt; field we can inspect to continue the traversal.&lt;/p&gt;

&lt;p&gt;Let's look at how we might perform a traversal to get at the root error&lt;br&gt;
value--be it a &lt;code&gt;WrappedError&lt;/code&gt;, &lt;code&gt;Error&lt;/code&gt;, or otherwise. We'll use a computed&lt;br&gt;
property--an&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get"&gt;object getter method&lt;/a&gt;--to&lt;br&gt;
allow us to compute and access the &lt;code&gt;root&lt;/code&gt; value like a property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;WrappedError&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Base case, no child === this instance is root&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// When the child is another node, compute recursively&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previous&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;WrappedError&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// This instance wraps the original error&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previous&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;let&lt;/span&gt; &lt;span class="nx"&gt;error1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the first error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;error2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WrappedError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the second error wraps #1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error1&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;error3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WrappedError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the third error wraps #2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;error2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;error1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the root of error2 should be strictly equal to error1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;error3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;error1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the root of error3 should be strictly equal to error1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Passes if no error appears in the console&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can test this example in&lt;br&gt;
&lt;a href="https://repl.it/@alexsasharegan/Wrapping-Errors-1"&gt;this repl here&lt;/a&gt;, but suffice&lt;br&gt;
it to say that the strict equality checks are all true. There's a lot we can do&lt;br&gt;
here, but simply logging with &lt;code&gt;console.error&lt;/code&gt; produces this output in Node.js&lt;br&gt;
&lt;em&gt;(from the same repl)&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt; WrappedError: the third error wraps &lt;span class="c"&gt;#2&lt;/span&gt;
    at evalmachine.&amp;lt;anonymous&amp;gt;:27:14
    at Script.runInContext &lt;span class="o"&gt;(&lt;/span&gt;vm.js:74:29&lt;span class="o"&gt;)&lt;/span&gt;
    at Object.runInContext &lt;span class="o"&gt;(&lt;/span&gt;vm.js:182:6&lt;span class="o"&gt;)&lt;/span&gt;
    at evaluate &lt;span class="o"&gt;(&lt;/span&gt;/run_dir/repl.js:133:14&lt;span class="o"&gt;)&lt;/span&gt;
    at ReadStream.&amp;lt;anonymous&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;/run_dir/repl.js:116:5&lt;span class="o"&gt;)&lt;/span&gt;
    at ReadStream.emit &lt;span class="o"&gt;(&lt;/span&gt;events.js:180:13&lt;span class="o"&gt;)&lt;/span&gt;
    at addChunk &lt;span class="o"&gt;(&lt;/span&gt;_stream_readable.js:274:12&lt;span class="o"&gt;)&lt;/span&gt;
    at readableAddChunk &lt;span class="o"&gt;(&lt;/span&gt;_stream_readable.js:261:11&lt;span class="o"&gt;)&lt;/span&gt;
    at ReadStream.Readable.push &lt;span class="o"&gt;(&lt;/span&gt;_stream_readable.js:218:10&lt;span class="o"&gt;)&lt;/span&gt;
    at fs.read &lt;span class="o"&gt;(&lt;/span&gt;fs.js:2124:12&lt;span class="o"&gt;)&lt;/span&gt;
  name: &lt;span class="s1"&gt;'WrappedError'&lt;/span&gt;,
  previous:
   &lt;span class="o"&gt;{&lt;/span&gt; WrappedError: the second error wraps &lt;span class="c"&gt;#1&lt;/span&gt;
    at evalmachine.&amp;lt;anonymous&amp;gt;:26:14
    at Script.runInContext &lt;span class="o"&gt;(&lt;/span&gt;vm.js:74:29&lt;span class="o"&gt;)&lt;/span&gt;
    at Object.runInContext &lt;span class="o"&gt;(&lt;/span&gt;vm.js:182:6&lt;span class="o"&gt;)&lt;/span&gt;
    at evaluate &lt;span class="o"&gt;(&lt;/span&gt;/run_dir/repl.js:133:14&lt;span class="o"&gt;)&lt;/span&gt;
    at ReadStream.&amp;lt;anonymous&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;/run_dir/repl.js:116:5&lt;span class="o"&gt;)&lt;/span&gt;
    at ReadStream.emit &lt;span class="o"&gt;(&lt;/span&gt;events.js:180:13&lt;span class="o"&gt;)&lt;/span&gt;
    at addChunk &lt;span class="o"&gt;(&lt;/span&gt;_stream_readable.js:274:12&lt;span class="o"&gt;)&lt;/span&gt;
    at readableAddChunk &lt;span class="o"&gt;(&lt;/span&gt;_stream_readable.js:261:11&lt;span class="o"&gt;)&lt;/span&gt;
    at ReadStream.Readable.push &lt;span class="o"&gt;(&lt;/span&gt;_stream_readable.js:218:10&lt;span class="o"&gt;)&lt;/span&gt;
    at fs.read &lt;span class="o"&gt;(&lt;/span&gt;fs.js:2124:12&lt;span class="o"&gt;)&lt;/span&gt;
     name: &lt;span class="s1"&gt;'WrappedError'&lt;/span&gt;,
     previous: Error: the first error
    at evalmachine.&amp;lt;anonymous&amp;gt;:25:14
    at Script.runInContext &lt;span class="o"&gt;(&lt;/span&gt;vm.js:74:29&lt;span class="o"&gt;)&lt;/span&gt;
    at Object.runInContext &lt;span class="o"&gt;(&lt;/span&gt;vm.js:182:6&lt;span class="o"&gt;)&lt;/span&gt;
    at evaluate &lt;span class="o"&gt;(&lt;/span&gt;/run_dir/repl.js:133:14&lt;span class="o"&gt;)&lt;/span&gt;
    at ReadStream.&amp;lt;anonymous&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;/run_dir/repl.js:116:5&lt;span class="o"&gt;)&lt;/span&gt;
    at ReadStream.emit &lt;span class="o"&gt;(&lt;/span&gt;events.js:180:13&lt;span class="o"&gt;)&lt;/span&gt;
    at addChunk &lt;span class="o"&gt;(&lt;/span&gt;_stream_readable.js:274:12&lt;span class="o"&gt;)&lt;/span&gt;
    at readableAddChunk &lt;span class="o"&gt;(&lt;/span&gt;_stream_readable.js:261:11&lt;span class="o"&gt;)&lt;/span&gt;
    at ReadStream.Readable.push &lt;span class="o"&gt;(&lt;/span&gt;_stream_readable.js:218:10&lt;span class="o"&gt;)&lt;/span&gt;
    at fs.read &lt;span class="o"&gt;(&lt;/span&gt;fs.js:2124:12&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Not bad, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Open For Extension
&lt;/h2&gt;

&lt;p&gt;The contextual references we're able to create with this provide a lot of&lt;br&gt;
opportunities for extension. Depending on the needs of your application, you&lt;br&gt;
might consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;spans&lt;/code&gt; getter to compute an array of all the stringified errors&lt;/li&gt;
&lt;li&gt;Memoize the getters by overwriting them after first access using
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty"&gt;&lt;code&gt;Object.defineProperty&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Make the list iterable by implementing
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator"&gt;&lt;code&gt;WrappedError.prototype[@@iterator]()&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Make iterator methods like &lt;code&gt;forEach&lt;/code&gt; or &lt;code&gt;map&lt;/code&gt; that implement
&lt;a href="https://blog.parametricstudios.com/posts/pattern-matching-custom-data-types/"&gt;pattern matching for your custom data types&lt;/a&gt;
&lt;em&gt;(like WrappedError, Error, and any)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've implemented the &lt;code&gt;spans&lt;/code&gt; property in the&lt;br&gt;
&lt;a href="https://repl.it/@alexsasharegan/Wrapping-Errors-1"&gt;repl link&lt;/a&gt; if you're&lt;br&gt;
curious. If you think of new applications or features for this idea, you can&lt;br&gt;
find me on Twitter at &lt;a href="https://twitter.com/AlexSashaRegan"&gt;@alexsasharegan&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>errors</category>
    </item>
    <item>
      <title>Pattern Matching Custom Data Types in Typescript</title>
      <dc:creator>Alex Regan</dc:creator>
      <pubDate>Sat, 02 Feb 2019 19:20:00 +0000</pubDate>
      <link>https://dev.to/alexsasharegan/pattern-matching-custom-data-types-in-typescript-4h87</link>
      <guid>https://dev.to/alexsasharegan/pattern-matching-custom-data-types-in-typescript-4h87</guid>
      <description>&lt;p&gt;Our application data comes in all shapes and sizes. We choose the best data&lt;br&gt;
structures for our problem, but when we need to put a variety of our data&lt;br&gt;
through the same pipeline, we have to manage safely distinguishing our data&lt;br&gt;
types and handling all their possible variations.&lt;/p&gt;

&lt;p&gt;In this post, I want to share a pattern I’ve discovered for working with&lt;br&gt;
different data types in a homogenous way. You can think of it as a functional&lt;br&gt;
programming version of the adapter pattern. I’ll introduce the concept of&lt;br&gt;
pattern matching, generic enums, and look at how we can leverage the power of&lt;br&gt;
TypeScript to mimic these patterns.&lt;/p&gt;

&lt;p&gt;The code examples here are hosted in a more fully functioning version at&lt;br&gt;
&lt;a href="https://github.com/alexsasharegan/colorjs"&gt;github.com/alexsasharegan/colorjs&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  What Is Pattern Matching?
&lt;/h1&gt;

&lt;p&gt;At its simplest, it's a control flow structure that allows you to match&lt;br&gt;
type/value patterns against a value. Pattern matching is usually a feature of&lt;br&gt;
functional programming languages like Haskell, Elixir, Elm, Reason, and more.&lt;br&gt;
Some languages, like Rust, offer pattern matching while not fitting neatly into&lt;br&gt;
the functional category. Consider this Rust code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"One"&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Two or Three"&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;10&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Four through Ten"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="mi"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I match everything else"&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 the &lt;code&gt;match&lt;/code&gt; expression evaluates &lt;code&gt;x&lt;/code&gt; against the patterns inside the block&lt;br&gt;
and then executes the corresponding match arm's expression/block. Patterns are&lt;br&gt;
evaluated and matched in top-down order. The first pattern is the literal value&lt;br&gt;
&lt;code&gt;1&lt;/code&gt;; the second matches &lt;strong&gt;either&lt;/strong&gt; a &lt;code&gt;2&lt;/code&gt; or a &lt;code&gt;3&lt;/code&gt;; the third describes a range&lt;br&gt;
pattern from &lt;code&gt;4&lt;/code&gt; to &lt;code&gt;10&lt;/code&gt;; the last pattern is a curious bit of syntax shared by&lt;br&gt;
many pattern matching systems that denotes a "catch-all" pattern that matches&lt;br&gt;
anything.&lt;/p&gt;

&lt;p&gt;Most pattern matching systems also come with compile-time exhaustiveness&lt;br&gt;
checking. The compiler checks all the match expressions and evaluates them to&lt;br&gt;
guarantee that one of the arms will be matched. If the compiler cannot guarantee&lt;br&gt;
the match expression is exhaustive, the program will fail to compile. Some&lt;br&gt;
compilers can also lint your match expressions to warn when a match arm shadows&lt;br&gt;
a subsequent match arm because it is more general than a later, more specific&lt;br&gt;
arm. Exhaustiveness checks are a really powerful tool to avoid bugs in our code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pattern Matching With Enums
&lt;/h2&gt;

&lt;p&gt;Enums exist in various languages, but apart from enumerating a named set, Rust's&lt;br&gt;
enum members are capable of holding values. Here's an example from&lt;br&gt;
&lt;a href="https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html"&gt;the rust book&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;IpAddr&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;V4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;V6&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;home&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;IpAddr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;V4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;127&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;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;loopback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;IpAddr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;V6&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"::1"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;IpAddr&lt;/code&gt; enum type has two members: &lt;code&gt;V4&lt;/code&gt; and &lt;code&gt;V6&lt;/code&gt;. Note that each can hold&lt;br&gt;
different types. This is a really powerful way to model real-world problems.&lt;br&gt;
Different cases often come with different data modeling concerns. An IPv4 can be&lt;br&gt;
easily modeled with a tuple of 4 bytes (&lt;code&gt;u8&lt;/code&gt;), while an IPv6 has many valid&lt;br&gt;
expressions that a string covers. Combining enums with values affords us a&lt;br&gt;
type-safe way to model each case with the optimal data structure.&lt;/p&gt;
&lt;h1&gt;
  
  
  Applying Pattern Matching In TypeScript
&lt;/h1&gt;

&lt;p&gt;Now let's see if we can implement some Rust-like enum and pattern matching&lt;br&gt;
capabilities. For our example, we're going to implement a color enum capable of&lt;br&gt;
matching against three distinct color types--RGB, HSL, and Hex. We'll start by&lt;br&gt;
stubbing out some classes. We could also use plain JavaScript objects, but we'll&lt;br&gt;
use classes for a little extra convenience.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;RGBColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HSLColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HexColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;hex&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you're unfamiliar with the empty-looking constructor syntax,&lt;br&gt;
&lt;a href="https://basarat.gitbooks.io/typescript/docs/classes.html#define-using-constructor"&gt;it's a shorthand to initialize properties&lt;/a&gt;.&lt;br&gt;
By declaring an access modifier (&lt;code&gt;public&lt;/code&gt;, &lt;code&gt;protected&lt;/code&gt;, &lt;code&gt;private&lt;/code&gt;), typescript&lt;br&gt;
automatically generates the code to assign the name of the constructor argument&lt;br&gt;
as a class property. It might feel a little like magic &lt;em&gt;(which I normally&lt;br&gt;
avoid)&lt;/em&gt;, but it's such a common pattern that I prefer to let the TS compiler&lt;br&gt;
reliably do the work for me.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Enum
&lt;/h2&gt;

&lt;p&gt;To start, we need to represent all our possible states. In our case, this will&lt;br&gt;
be the three color types. TypeScript has&lt;br&gt;
&lt;a href="https://www.typescriptlang.org/docs/handbook/enums.html"&gt;an enum type&lt;/a&gt;, but it&lt;br&gt;
does not hold generic values like in Rust. TS enums create a set of named&lt;br&gt;
constants of numbers or strings. We'll want to use string enums since they will&lt;br&gt;
play nicer later on when used as object keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;ColorFormat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;RGB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rbg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;HSL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hsl&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;Since &lt;code&gt;enum&lt;/code&gt; is not available in JS, I think it's worth looking at how&lt;br&gt;
TypeScript implements &lt;code&gt;enum&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RGB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rbg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HSL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hsl&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;ColorFormat&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ColorFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The TS compiler constructs a lookup table from our enum keys to their values&lt;br&gt;
using a plain JavaScript object. In the case of numeric enums, it also&lt;br&gt;
constructs a reverse lookup from values to keys in the same object. JS objects&lt;br&gt;
can only have strings, numbers &lt;em&gt;(which are cast to strings)&lt;/em&gt;, and symbols as&lt;br&gt;
keys, but TS only supports using string or number enums.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Discriminated Unions
&lt;/h2&gt;

&lt;p&gt;While the name sounds complex, the concept is straightforward. It's essentially&lt;br&gt;
a set of different object shapes that, while different, all share a common key.&lt;br&gt;
This key, &lt;strong&gt;the discriminant&lt;/strong&gt;, enables TypeScript to distinguish between the&lt;br&gt;
object types because its value &lt;strong&gt;is a literal value&lt;/strong&gt;. A literal value would be&lt;br&gt;
something like &lt;code&gt;"foo"&lt;/code&gt; instead of &lt;code&gt;string&lt;/code&gt;, or &lt;code&gt;1&lt;/code&gt; instead of &lt;code&gt;number&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's an example taken from&lt;br&gt;
&lt;a href="https://blog.mariusschulz.com/2016/11/03/typescript-2-0-tagged-union-types"&gt;Marius Schulz's TypeScript blog&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(which you should definitely check out)&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Cash&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&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;cash&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PayPal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&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;paypal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CreditCard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&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;credit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cardNumber&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;securityCode&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="c1"&gt;// PaymentMethod is the discriminated union of Cash, PayPal, and CreditCard&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PaymentMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Cash&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;PayPal&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;CreditCard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Each interface has a unique shape, but all share the key &lt;code&gt;kind&lt;/code&gt;. Notice the&lt;br&gt;
literal string values like &lt;code&gt;"credit"&lt;/code&gt; used in the discriminant. When you receive&lt;br&gt;
the type &lt;code&gt;PaymentMethod&lt;/code&gt;, TypeScript will not let you access any of the unique&lt;br&gt;
properties until you "discriminate" which shape it is by asserting the &lt;code&gt;kind&lt;/code&gt; is&lt;br&gt;
&lt;code&gt;"cash"&lt;/code&gt;, &lt;code&gt;"paypal"&lt;/code&gt;, or &lt;code&gt;"credit"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can use POJO's &lt;em&gt;(Plain Old&lt;br&gt;
JavaScript Objects)&lt;/em&gt; for our object types, or we can use classes. I'm going to&lt;br&gt;
use classes, but we're going to look at examples of both. Using classes will&lt;br&gt;
allow us to implement a more ergonomic match later on. We need to use the&lt;br&gt;
&lt;code&gt;readonly&lt;/code&gt; modifier on our discriminant key so the TS compiler knows the&lt;br&gt;
&lt;code&gt;format&lt;/code&gt; value won't change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// previous code omitted for brevity&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;RGBColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RGB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HSLColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HSL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HexColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hex&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;Color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;HexColor&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;RGBColor&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;HSLColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we've defined our union of possible colors. We used the classes as types&lt;br&gt;
here for brevity, but defining the colors as interfaces (which our classes&lt;br&gt;
satisfy) would make our union more flexible.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Matcher Objects
&lt;/h2&gt;

&lt;p&gt;Next we're going to create an object that behaves like our rust pattern match.&lt;br&gt;
The keys of our object will correspond with the values of our enum--this is why&lt;br&gt;
we needed to use string enums. Our values can't be expressions because in&lt;br&gt;
JavaScript they will be evaluated immediately. To ensure lazy evaluation only&lt;br&gt;
when a condition is matched, we need the values to be functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;ColorMatcher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Out&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;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hex&lt;/span&gt;&lt;span class="p"&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="nx"&gt;HexColor&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;Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HSL&lt;/span&gt;&lt;span class="p"&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="nx"&gt;HSLColor&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;Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RGB&lt;/span&gt;&lt;span class="p"&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="nx"&gt;RGBColor&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;Out&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;ColorMatcher&lt;/code&gt; object requires us to pass an object with all the keys&lt;br&gt;
present. This forces our code to handle all the possible states. Its also&lt;br&gt;
generic over a single return value type. This can feel limiting at first, but in&lt;br&gt;
practice reduces code complexity and bugs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Match Implementation
&lt;/h2&gt;

&lt;p&gt;Since we don't have real match semantics in JavaScript, we can make use of a&lt;br&gt;
&lt;code&gt;switch&lt;/code&gt; statement. Our function will need to accept as arguments: our &lt;code&gt;Color&lt;/code&gt;&lt;br&gt;
union type with the discriminant from step 2,&lt;br&gt;
and our matcher object from step 3. We'll switch on&lt;br&gt;
our color's discriminant property, and once the discriminant is matched by a&lt;br&gt;
case, TypeScript can infer the sub-type of &lt;code&gt;Color&lt;/code&gt; to be &lt;code&gt;Hex&lt;/code&gt;, &lt;code&gt;HSL&lt;/code&gt;, or &lt;code&gt;RGB&lt;/code&gt;.&lt;br&gt;
The compiler will also make sure we invoke the correct matcher function based on&lt;br&gt;
the inferred type. The implementation looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;matchColor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Out&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;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;matcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ColorMatcher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Out&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;Out&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;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;default&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;expectNever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&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;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hex&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;matcher&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hex&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;color&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;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HSL&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;matcher&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HSL&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;color&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;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RGB&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;matcher&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RGB&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;color&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;It's worth mentioning that when the &lt;code&gt;Color&lt;/code&gt; type is defined as a union of&lt;br&gt;
interfaces, the argument value can be either a POJO or a class instance--both&lt;br&gt;
types would satisfy the expected properties. Also note the helper func,&lt;br&gt;
&lt;code&gt;expectNever&lt;/code&gt;. The function leverages the &lt;code&gt;never&lt;/code&gt; type in a clever way to give&lt;br&gt;
us compile-time exhaustiveness checking. In short, the &lt;code&gt;never&lt;/code&gt; type is how&lt;br&gt;
TypeScript expresses an impossible state. If you'd like to know more, Marius&lt;br&gt;
Schulz has another great&lt;br&gt;
&lt;a href="https://mariusschulz.com/blog/typescript-2-0-the-never-type"&gt;blog post&lt;/a&gt; going&lt;br&gt;
deeper into the subject.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;expectNever&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;never&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Non exhaustive match.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since we opted to use classes, we can improve upon the &lt;code&gt;matchColor&lt;/code&gt; function by&lt;br&gt;
implementing a &lt;code&gt;match&lt;/code&gt; method each color class in our &lt;code&gt;Color&lt;/code&gt; union. Since the&lt;br&gt;
method is defined on the class, our match method implementation will only need&lt;br&gt;
the &lt;code&gt;ColorMatcher&lt;/code&gt; argument--a nice bonus for ergonomics. It can then call the&lt;br&gt;
correct the match "arm" with itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;RGBColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Out&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;matcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ColorMatcher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Out&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;Out&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;matcher&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RGB&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HSLColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Out&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;matcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ColorMatcher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Out&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;Out&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;matcher&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HSL&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HexColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Out&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;matcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ColorMatcher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Out&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;Out&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;matcher&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ColorFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hex&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Usage
&lt;/h2&gt;

&lt;p&gt;We've got all the pieces in place to finally start making using our color&lt;br&gt;
classes. We can start adding/refactoring functions to accept a &lt;code&gt;Color&lt;/code&gt;. This&lt;br&gt;
will allow callers to use whatever is most convenient to them--HSL, RGB, or Hex.&lt;/p&gt;

&lt;p&gt;We could use our &lt;code&gt;Color&lt;/code&gt; as a prop in components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&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="nx"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;BgColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`hsl(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;color&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="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;color&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="s2"&gt;%, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%)`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`rgb(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;color&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="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&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;color&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="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;color&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;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hex&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="p"&gt;});&lt;/span&gt;

   &lt;span class="k"&gt;return&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;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&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="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="p"&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;We could also implement some color conversion helpers and create some sass-like&lt;br&gt;
helpers like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;lighten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;percent&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;HSL&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;hsl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// Already our preferred type, so just return it.&lt;/span&gt;
    &lt;span class="na"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;convertRGBToHSL&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="na"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;convertHexToHSL&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="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&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="nx"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;percent&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;hsl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;darken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;percent&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;HSL&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;hsl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;convertRGBToHSL&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="na"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;convertHexToHSL&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="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max&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;hsl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;percent&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;hsl&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 HSL format is the easiest to lighten or darken, so these functions just&lt;br&gt;
convert to HSL, and then raise/lower the lightness. Notice that while the&lt;br&gt;
argument we accept is of type &lt;code&gt;Color&lt;/code&gt;, we return an &lt;code&gt;HSL&lt;/code&gt; instance. We could&lt;br&gt;
have chosen to return &lt;code&gt;Color&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;best practice&lt;/strong&gt; when using these&lt;br&gt;
tagged unions is to accept the widest&lt;br&gt;
(practical) range of types, but return the most exact type. If we returned&lt;br&gt;
&lt;code&gt;Color&lt;/code&gt; to our callers, they would need to match yet again to determine that we&lt;br&gt;
returned an HSL color--something we already knew.&lt;/p&gt;

&lt;h1&gt;
  
  
  Pros &amp;amp; Cons
&lt;/h1&gt;

&lt;p&gt;Matching custom data types with this pattern can be really powerful. Our code&lt;br&gt;
clearly documents all the possible states in our enums--a benefit for newcomers&lt;br&gt;
to our code as well as ourselves down the road. Our matcher objects also force&lt;br&gt;
us to acknowledge every possible state whenever we interact with our data. If&lt;br&gt;
we're in a hurry to implement a feature, the compiler is there to make sure we&lt;br&gt;
didn't forget anything. The matcher object's consistent return type will help us&lt;br&gt;
avoid bugs. It's hard to explain just how important this is, but in my&lt;br&gt;
experience, it's changed a lot about the way I code and reduced a lot of&lt;br&gt;
needless bugs.&lt;/p&gt;

&lt;p&gt;All the benefits don't come without a cost though. This pattern is quite verbose&lt;br&gt;
and requires a lot of boilerplate. We are mimicking syntax that doesn't exist in&lt;br&gt;
JavaScript, so the verbosity is an understandable trade-off, but one you'll have&lt;br&gt;
to consider when deciding whether or not your situation will be improved by&lt;br&gt;
using this pattern. As a library author, I find this to be a solid foundation on&lt;br&gt;
which to build my custom data types. I push the verbosity down to the library&lt;br&gt;
level so I can provide convenience and clarity to the library consumer.&lt;/p&gt;

&lt;p&gt;For further reading on this subject, you can check out a similar post by another&lt;br&gt;
community member, Manual Alabor:&lt;br&gt;
&lt;a href="https://pattern-matching-with-typescript.alabor.me/"&gt;https://pattern-matching-with-typescript.alabor.me/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my next couple of posts &lt;em&gt;(TBD)&lt;/em&gt;, I'm going explain some more functional&lt;br&gt;
programming-inspired patterns that leverage this matching pattern under the hood&lt;br&gt;
to provide an abstraction and a framework for handling nullable types, robust&lt;br&gt;
error handling, and creating robust, chainable task pipelines.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>functional</category>
    </item>
    <item>
      <title>Blog Launch</title>
      <dc:creator>Alex Regan</dc:creator>
      <pubDate>Sat, 29 Dec 2018 21:33:03 +0000</pubDate>
      <link>https://dev.to/alexsasharegan/blog-launch-1hgf</link>
      <guid>https://dev.to/alexsasharegan/blog-launch-1hgf</guid>
      <description>&lt;h1&gt;
  
  
  Welcome to the blog!
&lt;/h1&gt;

&lt;p&gt;I've been eager to start sharing tips, tricks, and the occasional tutorial for&lt;br&gt;
all things software. My business partner, Joel Cunningham, may wish contribute&lt;br&gt;
posts as well in his own field of expertise.&lt;/p&gt;

&lt;p&gt;In the spirit of talking shop, this blog has been launched on&lt;br&gt;
&lt;a href="https://www.netlify.com/"&gt;Netlify's&lt;/a&gt; amazing and free hosting services via our&lt;br&gt;
Github repository. We host most of our work on&lt;br&gt;
&lt;a href="https://www.digitalocean.com"&gt;DigitalOcean&lt;/a&gt;, but I wanted to take advantage of&lt;br&gt;
the continuous deployment perks that Netlify offers for&lt;br&gt;
&lt;a href="https://gohugo.io"&gt;Hugo&lt;/a&gt; static sites. We simply push to the master branch, and&lt;br&gt;
Netlify builds and deploys our site immediately! 🎉🎉🎉&lt;/p&gt;

&lt;p&gt;Thanks for stopping by! I'll have more to come soon. I've started what will&lt;br&gt;
probably be a multi-part series of posts about writing more robust JavaScript by&lt;br&gt;
using type systems to employ patterns I've learned from the&lt;br&gt;
&lt;a href="https://www.rust-lang.org/"&gt;Rust programming language&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;– Cheers 👋&lt;/p&gt;

</description>
      <category>announcements</category>
    </item>
  </channel>
</rss>
