<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ryan's Blog]]></title><description><![CDATA[Full Stack Developer]]></description><link>https://rlee.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 28 Apr 2026 08:12:15 GMT</lastBuildDate><atom:link href="https://rlee.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How To Use an ESM dependency in a library that exports ESM+CJS]]></title><description><![CDATA[A common problem Typescript library developers face is when importing libraries that only output ESM. For example [the standard library (@std) from the JSR repo](https://jsr.io/@std) only outputs ESM as according to Deno’s mandate. However for most T...]]></description><link>https://rlee.dev/how-to-use-an-esm-dependency-in-a-library-that-exports-esmcjs</link><guid isPermaLink="true">https://rlee.dev/how-to-use-an-esm-dependency-in-a-library-that-exports-esmcjs</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[esm]]></category><category><![CDATA[cjs]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Tue, 17 Dec 2024 06:17:29 GMT</pubDate><content:encoded><![CDATA[<p>A common problem Typescript library developers face is when importing libraries that only output ESM. For example [the standard library (@std) from the JSR repo](<a target="_blank" href="/s/io/jsr/G.https/@std" o-href="https://jsr.io/@std">https://jsr.io/@std</a>) only outputs ESM as according to Deno’s mandate. However for most Typescript library developers, this poses a problem because ESM cannot be directly imported into CJS.</p>
<p>This article provides a solution using [TSUP](<a target="_blank" href="/s/com/github/G.https/egoist/tsup" o-href="https://github.com/egoist/tsup">https://github.com/egoist/tsup</a>), a bundler for Typescript.</p>
<p><strong>Repro</strong>: <a target="_blank" href="/s/com/github/G.https/substrate-sdk/substrate-sdk/tree/master/packages/%40std" o-href="https://github.com/substrate-sdk/substrate-sdk/tree/master/packages/%40std">https://github.com/substrate-sdk/substrate-sdk/tree/master/packages/%40std</a></p>
<h2 id="heading-solution">Solution</h2>
<p>The solution to this problem is to re-export the library under a new package and then bundle it with TSUP but declare two entries in your `tsup.config.ts` file; one for ESM and one for CJS. Here is an example for re-exporting <code>@std/bytes</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// tsup.config.ts</span>
<span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'tsup'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig([
  {
    entry: {
      index: <span class="hljs-string">'src/mod.ts'</span>,
    },
    outDir: <span class="hljs-string">'dist/esm'</span>,
    format: [<span class="hljs-string">'esm'</span>],
    dts: <span class="hljs-literal">true</span>,
    sourcemap: <span class="hljs-literal">true</span>,
    clean: <span class="hljs-literal">true</span>,
  },
  {
    entry: {
      index: <span class="hljs-string">'src/mod.ts'</span>,
    },
    outDir: <span class="hljs-string">'dist/commonjs'</span>,
    format: [<span class="hljs-string">'cjs'</span>],
    dts: <span class="hljs-literal">true</span>,
    sourcemap: <span class="hljs-literal">true</span>,
    clean: <span class="hljs-literal">true</span>,
  },
])
</code></pre>
<p>Our source code simply looks like this</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/mod.ts</span>
<span class="hljs-keyword">export</span> * <span class="hljs-keyword">from</span> <span class="hljs-string">'@std/bytes'</span>
</code></pre>
<p>And our package.json would look something like this. Pay extra attention to the subpath exports where we define <code>import</code> and <code>require</code>.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"@substrate-sdk/std__bytes"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"0.0.0"</span>,
  <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Ryan Lee &lt;ryanleecode@gmail.com&gt;"</span>,
  <span class="hljs-attr">"type"</span>: <span class="hljs-string">"module"</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"./dist/commonjs/index.cjs"</span>,
  <span class="hljs-attr">"types"</span>: <span class="hljs-string">"./dist/commonjs/index.d.cts"</span>,
  <span class="hljs-attr">"module"</span>: <span class="hljs-string">"./dist/esm/index.js"</span>,
  <span class="hljs-attr">"exports"</span>: {
    <span class="hljs-attr">"./package.json"</span>: <span class="hljs-string">"./package.json"</span>,
    <span class="hljs-attr">"."</span>: {
      <span class="hljs-attr">"import"</span>: {
        <span class="hljs-attr">"@substrate-sdk/source"</span>: <span class="hljs-string">"./src/mod.ts"</span>,
        <span class="hljs-attr">"types"</span>: <span class="hljs-string">"./dist/esm/index.d.ts"</span>,
        <span class="hljs-attr">"default"</span>: <span class="hljs-string">"./dist/esm/index.js"</span>
      },
      <span class="hljs-attr">"require"</span>: {
        <span class="hljs-attr">"types"</span>: <span class="hljs-string">"./dist/commonjs/index.d.cts"</span>,
        <span class="hljs-attr">"default"</span>: <span class="hljs-string">"./dist/commonjs/index.cjs"</span>
      }
    }
  },
  <span class="hljs-attr">"repository"</span>: {
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"git"</span>,
    <span class="hljs-attr">"url"</span>: <span class="hljs-string">"https://github.com/substrate-sdk/substrate-sdk.git"</span>
  },
  <span class="hljs-attr">"keywords"</span>: [
    <span class="hljs-string">"bytes"</span>
  ],
  <span class="hljs-attr">"files"</span>: [
    <span class="hljs-string">"dist"</span>
  ],
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"prepare"</span>: <span class="hljs-string">"pnpm turbo build"</span>,
    <span class="hljs-attr">"clean"</span>: <span class="hljs-string">"rimraf dist"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"pnpm run clean &amp;&amp; tsup"</span>
  },
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"@std/bytes"</span>: <span class="hljs-string">"npm:@jsr/std__bytes@^1.0.4"</span>
  }
}
</code></pre>
<p>The full example can be found on github here: <a target="_blank" href="/s/com/github/G.https/substrate-sdk/substrate-sdk/tree/master/packages/%40std" o-href="https://github.com/substrate-sdk/substrate-sdk/tree/master/packages/%40std">https://github.com/substrate-sdk/substrate-sdk/tree/master/packages/%40std</a></p>
]]></content:encoded></item><item><title><![CDATA[How to Self Host Trigger.dev V2 the Right Way]]></title><description><![CDATA[If you're looking to use https://trigger.dev/, and want to use V2 you're going to want to self host since they aren't offering new customers to the V2 cloud platform.
First create an account at https://www.doppler.com/ and create a new project called...]]></description><link>https://rlee.dev/how-to-self-host-triggerdev-v2-the-right-way</link><guid isPermaLink="true">https://rlee.dev/how-to-self-host-triggerdev-v2-the-right-way</guid><category><![CDATA[Next.js]]></category><category><![CDATA[trigger.dev]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Wed, 05 Jun 2024 16:13:51 GMT</pubDate><content:encoded><![CDATA[<p>If you're looking to use <a target="_blank" href="/s/dev/trigger/G.https/" o-href="https://trigger.dev/">https://trigger.dev/</a>, and want to use V2 you're going to want to self host since they aren't offering new customers to the V2 cloud platform.</p>
<p>First create an account at <a target="_blank" href="/s/com/doppler/www/G.https/" o-href="https://www.doppler.com/">https://www.doppler.com/</a> and create a new project called trigger-v2.</p>
<p><img src="/s/com/hashnode/cdn/G.https/res/hashnode/image/upload/v1717603198884/96b61d26-6d2b-47eb-8f36-c5118dc06281.png" o-src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717603198884/96b61d26-6d2b-47eb-8f36-c5118dc06281.png" alt class="image--center mx-auto" /></p>
<p>Then follow the guide on the trigger docs for how to deploy to render.com with a few adjustments.</p>
<p><a target="_blank" href="/s/dev/trigger/G.https/docs/documentation/guides/self-hosting/render" o-href="https://trigger.dev/docs/documentation/guides/self-hosting/render">https://trigger.dev/docs/documentation/guides/self-hosting/render</a></p>
<ol>
<li><p>Go to <a target="_blank" href="/s/net/uuidgenerator/www/G.https/" o-href="https://www.uuidgenerator.net/">https://www.uuidgenerator.net/</a> and get two UUIDs. In the name field paste the UUId twice. We do this because the deployed render.com instance is publicly assessible to anyone on the web. So we are going to use <em>security by obsucation</em> to fudge the URL as much as possible to prevent people from landing our page.</p>
<p> <img src="/s/com/hashnode/cdn/G.https/res/hashnode/image/upload/v1717604094669/0ff54c2c-3262-4076-b3ac-952cd453200d.png" o-src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717604094669/0ff54c2c-3262-4076-b3ac-952cd453200d.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Instead of pasting the environment variables manually in render.com, add them to your doppler project and then use the integrations feature to synchronize it with your project.</p>
<p> <img src="/s/com/hashnode/cdn/G.https/res/hashnode/image/upload/v1717603452786/bcccad74-9e01-433e-8671-56e6dcdf6337.png" o-src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717603452786/bcccad74-9e01-433e-8671-56e6dcdf6337.png" alt class="image--center mx-auto" /></p>
<p> <img src="/s/com/hashnode/cdn/G.https/res/hashnode/image/upload/v1717603465622/8ccd3e4c-3874-4a4b-b240-e23067f90a77.png" o-src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717603465622/8ccd3e4c-3874-4a4b-b240-e23067f90a77.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Go to <a target="_blank" href="/s/tech/neon/G.https/" o-href="https://neon.tech/">https://neon.tech/</a> to get a serverless postgres database. Use this as the database environment variable.</p>
</li>
<li><p>Create a github app and link it to your project.</p>
</li>
</ol>
<p>Once its deployed, you can just go the deployed URL and login in with your github.</p>
<h2 id="heading-extras-nextjs-integration">Extras: Next.js Integration</h2>
<p>For next.js, you will probably want to integrate <a target="_blank" href="/s/dev/trigger/G.https/docs/documentation/guides/react-hooks-statuses" o-href="https://trigger.dev/docs/documentation/guides/react-hooks-statuses">status hooks</a> in your project. However the default settings won't work anymore because we are now self hosting.</p>
<p>Logically we will want to change the API url parameter in our <code>TriggerProvider</code>. However if we just use the same <code>render.com</code> url as our deployed instance, we are going to immediately lose our <em>security by obfuscation</em>, since anybody who lands on our web page can open the next console and see that URL.</p>
<p>Instead what we need is some kind of reverse proxy. We can leverage <a target="_blank" href="/s/org/nextjs/G.https/docs/pages/api-reference/next-config-js/rewrites" o-href="https://nextjs.org/docs/pages/api-reference/next-config-js/rewrites">Next.js rewrites</a> to do this.</p>
<p>First change your <code>apiUrl</code> to <code>/trigger-v2</code></p>
<p><img src="/s/com/hashnode/cdn/G.https/res/hashnode/image/upload/v1717603842918/bb6bfe41-cf1a-4b64-8b15-ef9d94462d07.png" o-src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717603842918/bb6bfe41-cf1a-4b64-8b15-ef9d94462d07.png" alt class="image--center mx-auto" /></p>
<p>Then in your <code>next.config.js</code>, add a rewrites parameter with <code>source: /trigger-v2/:api*</code> and <code>destination: ${env.TRIGGER_API_URL}/:api*</code> respectively.</p>
<p><img src="/s/com/hashnode/cdn/G.https/res/hashnode/image/upload/v1717603931437/048a6a0c-6d65-4e48-bc92-4546e06f8778.png" o-src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717603931437/048a6a0c-6d65-4e48-bc92-4546e06f8778.png" alt class="image--center mx-auto" /></p>
<p>Now your trigger react hooks will get reverse proxied to your deployed render.com instance.</p>
<p>If you liked this article feel free to drop me a DM or email!</p>
]]></content:encoded></item><item><title><![CDATA[Practical Use Cases for Effect-TS: Polling AI APIs]]></title><description><![CDATA[Intro
If you're new to Effect-TS, this is the start of a mini series where we'll explore practical use cases for it. Looking back at fp-ts, Effect-TS is a significant improvement because it enables true functional programming in a concurrent environm...]]></description><link>https://rlee.dev/practical-use-cases-for-effect-ts-polling-ai-apis</link><guid isPermaLink="true">https://rlee.dev/practical-use-cases-for-effect-ts-polling-ai-apis</guid><category><![CDATA[effect-ts]]></category><category><![CDATA[Functional Programming]]></category><category><![CDATA[concurrency]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Sun, 14 Apr 2024 05:26:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713072367936/1639c94b-0240-47eb-9707-901cb9d1ba57.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-intro">Intro</h2>
<p>If you're new to Effect-TS, this is the start of a mini series where we'll explore practical use cases for it. Looking back at fp-ts, Effect-TS is a significant improvement because it enables true functional programming in a concurrent environment.</p>
<p>Let's dive into a real-world example of using Effect-TS in a production setting. Imagine you're developing an application that uses image generation APIs. You need to wait for the images to render before proceeding, but you want to avoid the complexity of implementing webhooks. Instead, you'll use polling.</p>
<p>Here's a simplified diagram of the flow:</p>
<p><img src="/s/com/imgur/i/G.https/XXGLgnB.jpeg" o-src="https://i.imgur.com/XXGLgnB.jpeg" alt="Polling Flow" /></p>
<p>And here's the breakdown in plain English:</p>
<ol>
<li><p>Send a POST request to the API to generate an image based on a text prompt.</p>
</li>
<li><p>Receive a generation ID as the response.</p>
</li>
<li><p>Spawn a new thread to periodically check the status of the image generation using the provided ID. Keep looping until the status is "Complete" or "Failed".</p>
</li>
<li><p>Suspend the main thread until the image generation task completes.</p>
</li>
</ol>
<p>Effect-TS shines in scenarios like this, where you need to perform concurrent operations and handle asynchronous results in a functional way. It provides the tools to write clean, composable code that's easy to reason about, even in the presence of concurrency.</p>
<h2 id="heading-data-modelling">Data Modelling</h2>
<p>Lets write some interfaces to model what our AI APIs would look like</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> ImageGeneration = {
  id: <span class="hljs-built_in">string</span>;
} &amp; (
  | {
      status: <span class="hljs-string">'completed'</span>;
      url: <span class="hljs-built_in">string</span>;
    }
  | { status: <span class="hljs-string">'failed'</span>; error: <span class="hljs-built_in">string</span> }
  | { status: <span class="hljs-string">'pending'</span> }
);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> AiImageSDK = {
  generateImage(prompt: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span>&gt;;
  getGenerationById(id: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">Promise</span>&lt;ImageGeneration&gt;;
};
</code></pre>
<p>And now the code</p>
<pre><code class="lang-ts"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> client: AiImageSDK;

<span class="hljs-keyword">const</span> getImageGeneration = <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) =&gt;</span>
  Effect.Do.pipe(
    Effect.bind(<span class="hljs-string">'deferredUrl'</span>, <span class="hljs-function">() =&gt;</span> Deferred.make&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">Error</span>&gt;()),
    Effect.tap(<span class="hljs-function">(<span class="hljs-params">{ deferredUrl }</span>) =&gt;</span>
      Effect.tryPromise(<span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.getGenerationById(id);
        <span class="hljs-keyword">if</span> (response.status === <span class="hljs-string">'completed'</span>) {
          <span class="hljs-keyword">return</span> response.url;
        }
        <span class="hljs-keyword">if</span> (response.status === <span class="hljs-string">'failed'</span>) {
          <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Generation <span class="hljs-subst">${id}</span> failed.`</span>);
        }
      }).pipe(
        Effect.tap(<span class="hljs-function">(<span class="hljs-params">url</span>) =&gt;</span>
          url ? Deferred.succeed(deferredUrl, url) : Effect.none
        ),
        Effect.catchAllCause(<span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> Deferred.failCause(deferredUrl, c)),
        Effect.repeat(Schedule.spaced(<span class="hljs-string">'5 seconds'</span>)),
        Effect.forkScoped
      )
    ),
    Effect.flatMap(<span class="hljs-function">(<span class="hljs-params">{ deferredUrl }</span>) =&gt;</span> Deferred.await(deferredUrl))
  ).pipe(Effect.scoped);

<span class="hljs-keyword">await</span> Effect.Do.pipe(
  Effect.bind(<span class="hljs-string">'id'</span>, <span class="hljs-function">() =&gt;</span>
    Effect.tryPromise(<span class="hljs-keyword">async</span> () =&gt; client.generateImage(<span class="hljs-string">'shib army'</span>))
  ),
  Effect.bind(<span class="hljs-string">'url'</span>, <span class="hljs-function">(<span class="hljs-params">{ id }</span>) =&gt;</span> getImageGeneration(id)),
  Effect.map(<span class="hljs-function">(<span class="hljs-params">{ url }</span>) =&gt;</span> url),
  Effect.tap(Console.log)
).pipe(Effect.runPromise);
</code></pre>
<p>Lets break down the <code>getImageGeneration</code> function:</p>
<ol>
<li><p>We create a <code>Deferred</code> effect called <code>deferredUrl</code> representing the image url of the image that is being created.</p>
</li>
<li><p>We create a fork aka spawn a new non-blocking promise, to get the image generation. if the status is "completed" we return the url, if its "failed" we throw an error, if its "pending" we return <code>undefined</code>.</p>
</li>
<li><p>Once we reach a state where the status is completed successfully we assign the url to deferredUrl with <code>Deferred.succeed(deferredUrl, url)</code>. If the operation fails or encounters a defect, we use <code>Effect.catchAllCause((c) =&gt; Deferred.failCause(deferredUrl, c))</code> to propogate it back to the <code>Deferred</code> object.</p>
</li>
<li><p>This process repeats every 5 seconds until the function succeeds or fails. Once the URL is assigned, <code>Deferred.await(deferredUrl)</code> is unblocked and the effect is finished. Also take note of how the fork is scoped. The entire function is wrapped in Effect.scoped, meaning <code>Effect.forkScoped</code> will complete once the <code>Deferred</code> is unblocked.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p><img src="/s/com/imgur/i/G.https/920p4tL.png" o-src="https://i.imgur.com/920p4tL.png" alt="shib army" /></p>
<p>And thats how you do polling with effect-ts. Hope you leanred something!</p>
<p>If you have any questions or want to discuss this further, feel out to reach out. I'm available on Twitter or you can email me at ryanleecode@gmail.com.</p>
]]></content:encoded></item><item><title><![CDATA[Rust Pattern Matching Examples for Typescript Developers]]></title><description><![CDATA[Introduction
The reason why Typescript and Rust has been steadily gaining adoption is the superiority of their type systems compared to conventional programming languages like Java or Python. One thing that stands out about their type systems is thei...]]></description><link>https://rlee.dev/pattern-matching-examples</link><guid isPermaLink="true">https://rlee.dev/pattern-matching-examples</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[Rust]]></category><category><![CDATA[Functional Programming]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Mon, 18 Jan 2021 23:38:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1619908676588/6_-WQsyy1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>The reason why Typescript and Rust has been steadily gaining adoption is the superiority of their type systems compared to conventional programming languages like Java or Python. One thing that stands out about their type systems is their ability to do pattern matching.</p>
<p>In this post I'll give you an overview of what pattern matching is, how Typescript's <code>switch</code> statement works and its drawbacks. and I'll compare and contrast Rust pattern matching mechanics with Typescript's.</p>
<h2 id="what-is-pattern-matching">What is Pattern Matching?</h2>
<p>Pattern matching is a mechanism that is used to check if a value matches a particular pattern defined within a programming construct. Pattern matching is useful because we can succinctly check if a value has a certain set of properties without having to use multiple if-statements. Multiple if-statements are bad because they are verbose and you have to worry about dealing with nullable nested fields (i.e. checking if the property is null before checking the value).</p>
<p>Pattern matching is also useful for doing state management because it forces you to add a handler all the possible states that your type allows. If your type was a discriminated union, then your handler would handle all variants of the union. This prevents logic errors from creeping up into your programs because you can't accidentally forget to a handle a state.</p>
<p>Pattern matching is also commonly associated with <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Algebraic_data_type" o-href="https://en.wikipedia.org/wiki/Algebraic_data_type">algebraic data types</a> (ADTs) because ADTs can be decomposed into its constituent parts using pattern matching.</p>
<p>Lets look at some examples of pattern matching.</p>
<h2 id="example-1-the-switch-statement">Example 1 — The Switch Statement</h2>
<p>The only way to pattern match in Typescript is with the switch statement. Given a type that is a discriminated union, we can narrow the type using its discriminator.</p>
<p>For example in Redux, we use switch statements to match against different types of actions to update the state. The type of action is defined by its discriminator property <code>type</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Todo = {
  <span class="hljs-keyword">readonly</span> id: <span class="hljs-built_in">string</span>
  <span class="hljs-keyword">readonly</span> title: <span class="hljs-built_in">string</span>
  <span class="hljs-keyword">readonly</span> description: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">type</span> AddTodoAction = {
  <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">type</span>: <span class="hljs-string">'ADD_TODO'</span>
  <span class="hljs-keyword">readonly</span> todo: Todo
}

<span class="hljs-keyword">type</span> RemoveTodoAction = {
  <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">type</span>: <span class="hljs-string">'REMOVE_TODO'</span>
  <span class="hljs-keyword">readonly</span> id: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">type</span> Action = AddTodoAction | RemoveTodoAction

<span class="hljs-keyword">type</span> State = {
  <span class="hljs-keyword">readonly</span> todos: ReadonlyRecord&lt;<span class="hljs-built_in">string</span>, Todo&gt;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reducer</span>(<span class="hljs-params">state: State = { todos: {} }, action: Action</span>): <span class="hljs-title">State</span> </span>{
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_TODO'</span>:
      <span class="hljs-keyword">return</span> { todos: { ...state.todos, [action.todo.id]: action.todo } }
    <span class="hljs-keyword">case</span> <span class="hljs-string">'REMOVE_TODO'</span>: {
      <span class="hljs-keyword">const</span> { [action.id]: _, ...nextTodos } = state.todos
      <span class="hljs-keyword">return</span> { todos: nextTodos }
    }
  }
}
</code></pre>
<p>As evident in the example above, the type of <code>action</code> will be narrowed down to <code>AddTodoAction</code> when the <code>type</code> matches <code>ADD_TODO</code> and similarly narrowed down to <code>RemoveTodoAction</code> when the <code>type</code> matches <code>REMOVE_TODO</code>.</p>
<h3 id="drawbacks-of-switch-statements">Drawbacks of Switch Statements</h3>
<p><strong>1. Switch statements are verbose</strong></p>
<p>When you try to pattern match against nested ADTs, it adds verbosity because each level of nesting requires another switch state.</p>
<p>For example, the code snippet below is verbose because it uses two switch statements to decompose the <code>Option&lt;FooBar&gt;</code> type.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Option&lt;A&gt; = { _tag: <span class="hljs-string">'Some'</span>; value: A } | { _tag: <span class="hljs-string">'None'</span> }

<span class="hljs-keyword">type</span> Foo = {
  _tag: <span class="hljs-string">'Foo'</span>
}

<span class="hljs-keyword">type</span> Bar = {
  _tag: <span class="hljs-string">'Bar'</span>
}

<span class="hljs-keyword">type</span> FooBar = Foo | Bar

<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> foobar: FooBar

<span class="hljs-keyword">switch</span> (foobar._tag) {
  <span class="hljs-keyword">case</span> <span class="hljs-string">'Some'</span>:
    <span class="hljs-comment">// Double switch! 🤮</span>
    <span class="hljs-keyword">switch</span> (foobar.value._tag) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">'Foo'</span>:
        <span class="hljs-keyword">break</span>
      <span class="hljs-keyword">case</span> <span class="hljs-string">'Bar'</span>:
        <span class="hljs-keyword">break</span>
    }
    <span class="hljs-keyword">break</span>
  <span class="hljs-keyword">default</span>:
    <span class="hljs-keyword">break</span>
}
</code></pre>
<p>Alternatively you can introduce a second function and move the switch statement into it. This removes the nesting but still adds verbosity.</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleFooBar</span>(<span class="hljs-params">foobar: FooBar</span>) </span>{
  <span class="hljs-keyword">switch</span> (foobar._tag) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'Foo'</span>:
      <span class="hljs-keyword">break</span>
    <span class="hljs-keyword">case</span> <span class="hljs-string">'Bar'</span>:
      <span class="hljs-keyword">break</span>
  }
}

<span class="hljs-keyword">switch</span> (foobar._tag) {
  <span class="hljs-keyword">case</span> <span class="hljs-string">'Some'</span>:
    handleFooBar(foobar.value)
    <span class="hljs-keyword">break</span>
  <span class="hljs-keyword">default</span>:
    <span class="hljs-keyword">break</span>
}
</code></pre>
<p><strong>2. Switch Statements Cannot be Assigned to Variables</strong></p>
<p>If you want to assign the result of a switch statement to a variable, you need to wrap into a function, which adds verbosity.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Very verbose! 😡</span>
<span class="hljs-keyword">const</span> fibonacci = (<span class="hljs-function">(<span class="hljs-params">n: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (n) {
    <span class="hljs-keyword">case</span> <span class="hljs-number">0</span>:
      <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>
    <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:
      <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> n + n - <span class="hljs-number">1</span>
  }
})(<span class="hljs-number">100</span>)
</code></pre>
<p><strong>3. Discriminators can only be primitive fields</strong></p>
<p>Third, you can only switch on primitive fields: i.e. <code>string</code> and <code>number</code>. Switching on an object does not work.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> foo = { bar: <span class="hljs-string">'baz'</span> }

<span class="hljs-keyword">switch</span> (foo) {
  <span class="hljs-keyword">case</span> { bar: <span class="hljs-string">'baz'</span> }:
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'foobarbaz'</span>) ❌
    <span class="hljs-keyword">break</span>
  <span class="hljs-keyword">default</span>:
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'nope.jpg'</span>) 😢
    <span class="hljs-keyword">break</span>
}
</code></pre>
<p>From a pattern matching perspective, Typescript is very limited in what it can do. Hence, this makes writing functional code more verbose and requires more boilerplate because you'll need to write your own matchers. See <a target="_blank" href="/s/com/github/G.https/pfgray/ts-adt" o-href="https://github.com/pfgray/ts-adt">ts-adt</a> as an example.</p>
<h2 id="example-2-the-match-statement">Example 2 — The Match Statement</h2>
<p>In Rust, we don't have switch statements, we have match statements. Match statements are like Typescript switch statements but without all the drawbacks.</p>
<p><strong>1. Match statements are concise</strong></p>
<p>Here's an example of same redux code but written in Rust; written mutably for extra brevity.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::collections::HashMap;

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Todo</span></span> {
    id: <span class="hljs-built_in">String</span>,
    title: <span class="hljs-built_in">String</span>,
    description: <span class="hljs-built_in">String</span>
}

<span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Action</span></span> {
    AddTodoAction { todo: Todo },
    RemoveTodoAction { id: <span class="hljs-built_in">String</span> }
}

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">State</span></span> {
    todos: HashMap&lt;<span class="hljs-built_in">String</span>, Todo&gt;
}

<span class="hljs-keyword">impl</span> <span class="hljs-built_in">Default</span> <span class="hljs-keyword">for</span> State {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">default</span></span>() -&gt; State {
        State { todos: HashMap::new() }
    }
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">reducer</span></span>(state: &amp;<span class="hljs-keyword">mut</span> State, action: Action) {
    <span class="hljs-keyword">match</span> action {
        Action::AddTodoAction { todo } =&gt; {
            state.todos.insert(todo.id.clone(), todo);
        },
        Action::RemoveTodoAction { id } =&gt; {
            state.todos.remove(&amp;id);
        }
    }
}
</code></pre>
<p>How is this more concise?</p>
<p>First, because Rust is nominally typed rather than structurally typed, so we don't need a <code>type</code> discriminator field.</p>
<p>Second, we leverage Rust's enum syntax to destructure fields directly in a match statement as demonstrated with <code>Action::AddTodoAction { todo }</code>.</p>
<p><strong>2. No Nested Matches</strong></p>
<p>The same foobar example shown in the Typescript example can be written in Rust like so:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">FooBar</span></span> {
    Foo,
    Bar
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> foobar: <span class="hljs-built_in">Option</span>&lt;FooBar&gt; = <span class="hljs-literal">Some</span>(FooBar::Foo);
    <span class="hljs-keyword">match</span> foobar {
        <span class="hljs-literal">Some</span>(FooBar::Foo) =&gt; {}
        <span class="hljs-literal">Some</span>(FooBar::Bar) =&gt; {}
        _ =&gt; {}
    }
}
</code></pre>
<p>You can see how advantageous this is compared to Typescript because you can just construct the values you want to match against directly as demonstrated by <code>Some(FooBar::Foo)</code>.</p>
<p>Heres a more complicated example where we match against certain fields and ignore the fields we don't care about using the <code>..</code> syntax. The <code>..</code> syntax is analogous to Typescript's <code>...</code>.</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Cube</span></span> {
    length: <span class="hljs-built_in">u32</span>,
    width: <span class="hljs-built_in">u32</span>,
    height: <span class="hljs-built_in">u32</span>
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> my_cube = Cube {
        length: <span class="hljs-number">10</span>,
        width: <span class="hljs-number">5</span>,
        height: <span class="hljs-number">5</span>
    };

    <span class="hljs-keyword">match</span> my_cube {
        <span class="hljs-comment">// only match cubes of length 10</span>
        Cube { length: <span class="hljs-number">10</span>, .. } =&gt; {},
        _ =&gt; {}
    }
}
</code></pre>
<p>You can also name the parameters you match.</p>
<pre><code class="lang-rust">Cube { length: cube_length @ <span class="hljs-number">10</span> , .. } =&gt; {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, cube_length); <span class="hljs-comment">// cube length is a variable</span>
},
</code></pre>
<p>And if you use an unstable feature, you can match the cube length against a range as well.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#![feature(exclusive_range_pattern)]</span>

<span class="hljs-comment">// only match cubes of length (10-15]</span>
Cube { length: cube_length @ <span class="hljs-number">10</span>..<span class="hljs-number">15</span> , .. } =&gt; {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, cube_length);
},
</code></pre>
<h2 id="example-3-the-if-let-statement">Example 3 — The If-Let Statement</h2>
<p>In the previous example we wrote a full <code>match</code> statement to match against a very specific variant of a cube but we discarded the other variants.</p>
<p>If we don't care about other variants, then a succinct way of pattern matching is using an <code>if-let</code> statement.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> Cube { length: cube_length @ <span class="hljs-number">10</span>, .. } = my_cube {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, cube_length);
}
</code></pre>
<p>This makes writing pattern matching code idiomatic.</p>
<p>There are problems though; you can't chain <code>if-let</code> statements with conditionals.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> my_cond = <span class="hljs-literal">true</span>;
<span class="hljs-comment">// ❌ Syntax Error</span>
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">let</span> Cube { length: cube_length @ <span class="hljs-number">10</span>, .. } = my_cube) &amp;&amp; my_cond {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, cube_length);
}
</code></pre>
<p>But you can just add the conditional into a tuple and pattern match against the tuple.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> (Cube { length: cube_length @ <span class="hljs-number">10</span>, .. }, <span class="hljs-literal">true</span>) = (my_cube, my_cond) {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, cube_length);
}
</code></pre>
<h2 id="example-4-rust-matching-slices">Example 4 — Rust: Matching Slices</h2>
<p>In Rust, not only can you match against structs and enums, but you can also match against slices.</p>
<p>Here is a basic example matching against an empty slice.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> [<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>] = [<span class="hljs-number">0</span>; <span class="hljs-number">3</span>] {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"woah"</span>);
}
</code></pre>
<p>A more sophisticated example is matching against a vector with a known size.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> my_vec = <span class="hljs-built_in">vec!</span>[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>];
<span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> &amp;[<span class="hljs-number">1</span>, x, <span class="hljs-number">3</span>] = &amp;*my_vec {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, x); <span class="hljs-comment">// 2</span>
}
</code></pre>
<p>Note, dereferencing <code>my_vec</code> with <code>*</code> turns the vector into a slice. The slice on the right then needs to be borrowed and matched against a borrowed slice on the left. This is because an owned slice is not sized and will fail compilation.</p>
<p>For vectors where we don't know the size we can replace the parts we don't care about matching with <code>..</code>.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> my_vec = <span class="hljs-built_in">vec!</span>[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>];
<span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> &amp;[<span class="hljs-number">1</span>, .., <span class="hljs-number">4</span>, <span class="hljs-number">5</span>] = &amp;*v {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"wow!"</span>);
}
</code></pre>
<p>The caveat is we can only match the head and the tail, we can't use the <code>..</code> operator more than once. For example, this won't compile.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> &amp;[<span class="hljs-number">1</span>, .., <span class="hljs-number">3</span>, .., <span class="hljs-number">5</span>] = &amp;*v {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"this doesn't compile!"</span>);
}
</code></pre>
<h2 id="conclusion">Conclusion</h2>
<p>You should now understand the differences between Typescript and Rust pattern matching. Rust lets you do advanced pattern matching while Typescript is limited to basic switch statements and discriminated unions. The takeaway is the more complex your types are, the more you should consider languages like Rust, or even Scala because of their advanced pattern matching techniques.</p>
<p>Thanks for reading! If you enjoyed this post, please consider sharing.</p>
]]></content:encoded></item><item><title><![CDATA[Practical Guide to Fp-ts P6: The Do Notation]]></title><description><![CDATA[⚠️ Disclaimer Warning
  
    fp-ts is now dead. Please use effect-ts instead.
  
  
    Update 2024: effect-ts is the recommended library for functional programming in TypeScript.
  


Introduction
Welcome back to Part 6 of The Practical Guide to fp-...]]></description><link>https://rlee.dev/practical-guide-to-fp-ts-p6-the-do-notation</link><guid isPermaLink="true">https://rlee.dev/practical-guide-to-fp-ts-p6-the-do-notation</guid><category><![CDATA[Functional Programming]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Mon, 30 Nov 2020 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1618067197587/ok0MPbit6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div>
  <h3>⚠️ Disclaimer Warning</h3>
  <p>
    <strong>fp-ts</strong> is now dead. Please use <a href="/s/website/effect/G.https/" o-href="https://effect.website/" target="_blank"><strong>effect-ts</strong></a> instead.
  </p>
  <p>
    <em>Update 2024: effect-ts is the recommended library for functional programming in TypeScript.</em>
  </p>
</div>

<h2 id="heading-introduction">Introduction</h2>
<p>Welcome back to Part 6 of The Practical Guide to fp-ts. So far I've covered the basics of functional programming and fp concepts. Now I will shift to more advanced topics.</p>
<p>In this post, I will formally introduce what a monad is and how we can use the <code>Do</code> Notation to simplify writing monadic code.</p>
<h2 id="heading-what-is-a-monad">What is a Monad?</h2>
<p>By now, you may have noticed I haven't said the term <em>monad</em> once in this entire series. This was intentional. The term monad creates a lot of confusion for newcomers to functional programming because there are many interpretations for what a monad is.</p>
<p>But even though I haven't said the term <em>monad</em>, you've been using monads throughout this entire series. Option is a monad. Either is a monad. Task is a monad.</p>
<p>So what is a monad?</p>
<p>A monad is any type that has the following instance methods:</p>
<ol>
<li><code>of</code></li>
<li><code>map</code></li>
<li><code>chain (flatmap)</code></li>
<li><code>ap</code></li>
</ol>
<p>In addition it the implementation of these methods must satisfy the following monadic laws:</p>
<ol>
<li>Left Identity: <code>of(x).chain(f) == of(f(x))</code></li>
<li>Right Identity: <code>of(x).chain(of) = of(x)</code></li>
<li>Associativity: <code>of(x).chain(f).chain(g) = of(x).chain(flow(f, g))</code></li>
</ol>
<h3 id="heading-are-monads-containers">Are Monads Containers?</h3>
<p>A common belief about monads is that they are containers. Some might refer to them as "ships in a bottle". Even though there exist some monads that would satisfy the definition of a container, not all monads are containers.</p>
<p>Lets see why.</p>
<p>When we look at the Option monad, its clear that it operates as a container over a nullable type. Its either <code>Some(x)</code> or <code>None</code>. Just like how Either is either <code>Left</code> or <code>Right</code> over some value <code>x</code>.</p>



<p>Can we create a type that satisfies monadic properties but isn't a container? Yes we can. Just change the all the option methods to return <code>None</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> None {
  <span class="hljs-keyword">readonly</span> _tag: <span class="hljs-string">'None'</span>
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Some&lt;A&gt; {
  <span class="hljs-keyword">readonly</span> _tag: <span class="hljs-string">'Some'</span>
  <span class="hljs-keyword">readonly</span> value: A
}
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">type</span> Option&lt;A&gt; = None | Some&lt;A&gt;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> none: Option&lt;<span class="hljs-built_in">never</span>&gt;

<span class="hljs-comment">// this option "contains" nothing</span>
<span class="hljs-keyword">const</span> option = {
  <span class="hljs-keyword">of</span>: &lt;A&gt;<span class="hljs-function">(<span class="hljs-params">a: A</span>) =&gt;</span> none,
  map: &lt;A, B&gt;(fa: Option&lt;A&gt;, f: <span class="hljs-function">(<span class="hljs-params">a: A</span>) =&gt;</span> B) =&gt; none,
  chain: &lt;A, B&gt;(fa: Option&lt;A&gt;, f: <span class="hljs-function">(<span class="hljs-params">a: A</span>) =&gt;</span> Option&lt;B&gt;) =&gt; none,
  ap: &lt;A, B&gt;(fab: Option&lt;<span class="hljs-function">(<span class="hljs-params">a: A</span>) =&gt;</span> B&gt;, fa: Option&lt;A&gt;) =&gt; none,
}
</code></pre>
<p>Now our new "Option" is clearly not a container but it is still a monad. So it is not enough to describe monads as containers.</p>
<p>Instead, I will implore you with <a target="_blank" href="/s/dev/rlee/G.https/@YuriyBogomolov" o-href="@YuriyBogomolov">@YuriyBogomolov</a> definition of a monad.</p>



<h2 id="heading-the-do-notation">The Do Notation</h2>
<p>Understanding monads is key to understanding the Do notation. But before we jump in, lets first understand the motivation for the Do notation.</p>
<p>The most common hurdle people run into when using monads is maintaining variable scope when using the <code>chain</code> operator.</p>
<p>Lets build up an example to demonstrate this.</p>
<p>First, lets define 3 functions returning a <code>Task</code> monad.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> T <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Task'</span>

<span class="hljs-comment">// filler values for brevity</span>
<span class="hljs-keyword">type</span> A = <span class="hljs-string">'A'</span>
<span class="hljs-keyword">type</span> B = <span class="hljs-string">'B'</span>
<span class="hljs-keyword">type</span> C = <span class="hljs-string">'C'</span>

<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> fa: <span class="hljs-function">() =&gt;</span> T.Task&lt;A&gt;
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> fb: <span class="hljs-function">(<span class="hljs-params">a: A</span>) =&gt;</span> T.Task&lt;B&gt;
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> fc: <span class="hljs-function">(<span class="hljs-params">ab: { a: A; b: B }</span>) =&gt;</span> T.Task&lt;C&gt;
</code></pre>
<p>In order to call <code>fc</code> we need to have access to the return values of <code>fa</code> and <code>fb</code>. If we want to normally <em>chain</em> these set of function calls, we would need to nest our chain calls to keep previous variables in scope.</p>
<p>Like so.</p>
<pre><code class="lang-ts">T.task.chain(fa(), <span class="hljs-function">(<span class="hljs-params">a</span>) =&gt;</span> T.task.chain(fb(a), <span class="hljs-function">(<span class="hljs-params">b</span>) =&gt;</span> fc({ a, b }))) <span class="hljs-comment">// Task&lt;"C"&gt;</span>
</code></pre>
<p>This is in contrast to what we would normally write, which looks like this:</p>
<pre><code class="lang-ts">flow(fa, T.chain(fb), T.chain(fc)) <span class="hljs-comment">// ❌ "a" will go out of scope</span>
</code></pre>
<p>So how can we achieve something that looks similar to the above? We can use the Do notation!</p>
<hr />
<p>The Do notation is similar to <code>sequenceT</code> and <code>sequenceS</code> in the sense that you need to provide it an instance. The difference is, sequences require the instance to be of the <code>Apply</code> type (<code>ap</code> + <code>map</code>) while Do requires a <code>Monad</code> type (<code>ap</code> + <code>map</code> + <code>chain</code> + <code>of</code>).</p>
<p>So lets look at the same code but using the Do notation instead.[^1]</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { Do } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts-contrib/lib/Do'</span>

Do(T.task)
  .bind(<span class="hljs-string">'a'</span>, fa()) <span class="hljs-comment">// task</span>
  .bindL(<span class="hljs-string">'b'</span>, <span class="hljs-function">(<span class="hljs-params">{ a } /* context */</span>) =&gt;</span> fb(a)) <span class="hljs-comment">// lazy task</span>
  .bindL(<span class="hljs-string">'c'</span>, fc) <span class="hljs-comment">// lazy task</span>
  .return(<span class="hljs-function">(<span class="hljs-params">{ c }</span>) =&gt;</span> c) <span class="hljs-comment">// Task&lt;"C"&gt;</span>
</code></pre>
<p>What <code>Do</code> does here is, it lets you keep the <code>bind</code> the result of each task to a context variable. The first parameter in <code>bind</code> is the name of the variable. The second is the value.</p>
<p>You may also notice there are two variants of bind: <code>bind</code> and <code>bindL</code>. The <code>L</code> suffix stands for lazy. In this example, we don't directly provide a <code>Task</code> to <code>bindL</code>, we provide a function where the parameter is the context and the return value is a <code>Task</code>.</p>
<p>And at the very end of the Do notation we add a <code>return</code> call. In the previous example, we went from <code>fa -&gt; fb -&gt; fc</code> to form the <code>Task&lt;"C"&gt;</code>. With the Do notation we need to specify what we want to return because just binding variables leaves us in an undefined state.</p>
<p>You can also view this from the imperative lens, where <code>fa</code>, <code>fb</code>, and <code>fc</code> are synchronous functions rather than monads.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> fa: <span class="hljs-function">() =&gt;</span> A
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> fb: <span class="hljs-function">(<span class="hljs-params">a: A</span>) =&gt;</span> B
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> fc: <span class="hljs-function">(<span class="hljs-params">ab: { a: A; b: B }</span>) =&gt;</span> C
;<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> a = fa()
  <span class="hljs-keyword">const</span> b = fb(a)
  <span class="hljs-keyword">const</span> c = fc({ a, b })

  <span class="hljs-keyword">return</span> c
}
</code></pre>
<p>If we wanted to introduce a side effect, say <code>console.log</code>, its easy in the imperative world.</p>
<pre><code class="lang-ts">;<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> a = fa()
  <span class="hljs-keyword">const</span> b = fb(a)

  <span class="hljs-built_in">console</span>.log(b) <span class="hljs-comment">// 👈 side effect</span>

  <span class="hljs-keyword">const</span> c = fc({ a, b })

  <span class="hljs-keyword">return</span> c
}
</code></pre>
<p>With Do notation we can do the same with a <code>do</code> invocation.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { log } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Console'</span>

Do(T.task)
  .bind(<span class="hljs-string">'a'</span>, fa())
  .bindL(<span class="hljs-string">'b'</span>, <span class="hljs-function">(<span class="hljs-params">{ a }</span>) =&gt;</span> fb(a))
  .doL(<span class="hljs-function">(<span class="hljs-params">{ b }</span>) =&gt;</span> pipe(log(b), T.fromIO)) <span class="hljs-comment">// 👈 side effect</span>
  .bindL(<span class="hljs-string">'c'</span>, fc)
  .return(<span class="hljs-function">(<span class="hljs-params">{ c }</span>) =&gt;</span> c)
</code></pre>
<p><code>Do</code> is different from <code>bind</code> in the sense that it doesn't take a name as its first argument. This means it won't be added to the context.</p>
<p>If you want a more in-depth post about the <code>Do</code> notation, check our Paul Gray's <a target="_blank" href="/s/net/paulgray/G.https/do-syntax-in-typescript/" o-href="https://paulgray.net/do-syntax-in-typescript/">post</a> where he covers all the Do methods.</p>
<h2 id="heading-the-built-in-do-notation">The Built-In Do Notation</h2>
<p>One of the problems with the Do notation from the <code>fp-ts-contrib</code> package is its inflexibility. Every <code>bind</code> must be a monad representing the instance passed in. This means we can't switch categories from say <code>Task</code> to <code>TaskEither</code>. In our example, we are limited to <code>Task</code> because we used <code>Do(T.task)</code>.</p>
<p>If we were to introduce a 4th function that returns a <code>TaskEither</code>, we would need to replace our instance with <code>taskEither</code> and lift each <code>Task</code> into <code>TaskEither</code>, which is not ideal because it becomes more verbose.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> TE <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/TaskEither'</span>

<span class="hljs-keyword">type</span> D = <span class="hljs-string">'D'</span>
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> fd: <span class="hljs-function">(<span class="hljs-params">ab: { a: A; b: B; c: C }</span>) =&gt;</span> TE.TaskEither&lt;D, <span class="hljs-built_in">Error</span>&gt;

Do(TE.taskEither)
  .bind(<span class="hljs-string">'a'</span>, TE.fromTask(fa()))
  .bindL(<span class="hljs-string">'b'</span>, <span class="hljs-function">(<span class="hljs-params">{ a }</span>) =&gt;</span> TE.fromTask(fb(a)))
  .doL(<span class="hljs-function">(<span class="hljs-params">{ b }</span>) =&gt;</span> pipe(log(b), T.fromIO, TE.fromTask))
  .bindL(<span class="hljs-string">'c'</span>, <span class="hljs-function">(<span class="hljs-params">{ a, b }</span>) =&gt;</span> TE.fromTask(fc({ a, b })))
  .return(<span class="hljs-function">(<span class="hljs-params">{ c }</span>) =&gt;</span> c)
</code></pre>
<p>Instead, fp-ts has its own notation for binding where we can switch between different monads with ease.[^2]</p>
<pre><code class="lang-ts">pipe(
  T.bindTo(<span class="hljs-string">'a'</span>)(fa()),
  T.bind(<span class="hljs-string">'b'</span>, <span class="hljs-function">(<span class="hljs-params">{ a }</span>) =&gt;</span> fb(a)),
  T.chainFirst(<span class="hljs-function">(<span class="hljs-params">{ b }</span>) =&gt;</span> pipe(log(b), T.fromIO)),
  T.bind(<span class="hljs-string">'c'</span>, <span class="hljs-function">(<span class="hljs-params">{ a, b }</span>) =&gt;</span> fc({ a, b })),
  TE.fromTask,
  TE.bind(<span class="hljs-string">'d'</span>, <span class="hljs-function">(<span class="hljs-params">{ a, b, c }</span>) =&gt;</span> fd({ a, b, c })),
  TE.map(<span class="hljs-function">(<span class="hljs-params">{ d }</span>) =&gt;</span> d),
)
</code></pre>
<p>You can see that the advantage of this approach is the ease of switching between different categories of monads. Hence, I strongly recommend you use this notation over the <code>Do</code> notation from the <code>fp-ts-contrib</code> package.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The Do notation is a powerful way of writing monadic code that makes it easy to chain functions while at the same time maintaining variable scope. Its inspired by the <a target="_blank" href="/s/org/wikibooks/en/G.https/wiki/Haskell/do_notation" o-href="https://en.wikibooks.org/wiki/Haskell/do_notation">Haskell Do notation</a> and Scala's <a target="_blank" href="/s/com/eed3si9n/G.https/herding-cats/do-vs-for.html" o-href="https://eed3si9n.com/herding-cats/do-vs-for.html">for-yield notation</a>.</p>
<p>In Typescript, we can use the Do notation from the <code>fp-ts-contrib</code> package or the built in <code>bind</code> methods. But there's another notation thats being discussed on the <a target="_blank" href="/s/com/github/G.https/gcanti/fp-ts/issues/261#issuecomment-682257194" o-href="https://github.com/gcanti/fp-ts/issues/261#issuecomment-682257194">fp-ts Github</a>. It proposes using function generators and along with <code>yield</code> syntax to make monadic code look imperative. Its an interesting approach and definitely worth investigating further.</p>
<p>Lastly, if you're interested in my content, be sure to follow me on <a target="_blank" href="/s/com/twitter/G.https/ryanleecode" o-href="https://twitter.com/ryanleecode">Twitter</a>.</p>
<p>Until next time.</p>
<hr />
<p>[^1]: Note this comes from the <a target="_blank" href="/s/com/npmjs/www/G.https/package/fp-ts-contrib" o-href="https://www.npmjs.com/package/fp-ts-contrib">fp-ts-contrib</a> package.</p>
<p>[^2]: Note <code>chainFirst</code> is the equivalent of <code>doL</code>.</p>
]]></content:encoded></item><item><title><![CDATA[Practical Guide to Fp-ts P5: Apply, Sequences, and Traversals]]></title><description><![CDATA[⚠️ Disclaimer Warning
  
    fp-ts is now dead. Please use effect-ts instead.
  
  
    Update 2024: effect-ts is the recommended library for functional programming in TypeScript.
  


Introduction
Welcome to part 5 of this series on learning fp-ts t...]]></description><link>https://rlee.dev/practical-guide-to-fp-ts-part-5</link><guid isPermaLink="true">https://rlee.dev/practical-guide-to-fp-ts-part-5</guid><category><![CDATA[Functional Programming]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Thu, 01 Oct 2020 14:58:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1618066675712/AwgUihxqY.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div>
  <h3>⚠️ Disclaimer Warning</h3>
  <p>
    <strong>fp-ts</strong> is now dead. Please use <a href="/s/website/effect/G.https/" o-href="https://effect.website/" target="_blank"><strong>effect-ts</strong></a> instead.
  </p>
  <p>
    <em>Update 2024: effect-ts is the recommended library for functional programming in TypeScript.</em>
  </p>
</div>

<h2 id="heading-introduction">Introduction</h2>
<p>Welcome to part 5 of this series on learning fp-ts the practical way.</p>
<p>By now you've been introduced to the operators <code>of</code>, <code>map</code>, <code>chain</code>, <code>flatten</code>, but there's one operator we haven talked about yet: <code>ap</code> or <em>apply</em>. The <code>ap</code> operator is a greater part of what is called an Applicative. And applicatives form the basis for sequences and traversals.</p>
<p>In this post, I will explain the rationale for <code>ap</code>, its usecases, and how we don't actually need it because we have sequences and traversals.</p>
<h2 id="heading-apply">Apply</h2>

<p>What is the mysterious <code>ap</code> operator, otherwise known as Apply?</p>
<p>In many ways, it is like the reverse of <code>map</code>. Rather than piping a value into a function, you pipe a function into a value.</p>
<p>To demonstrate this, lets learn about <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Currying" o-href="https://en.wikipedia.org/wiki/Currying">currying</a>. Currying is taking a function with multiple parameters and converting it into a higher order function such that it takes a single argument repeatedly.</p>
<p>For example, we can have a <code>write</code> function that takes 3 parameters.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">write</span>(<span class="hljs-params">key: <span class="hljs-built_in">string</span>, value: <span class="hljs-built_in">string</span>, flush: <span class="hljs-built_in">boolean</span></span>): <span class="hljs-title">unknown</span></span>
</code></pre>
<p>And we can convert it into a curried function like so:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> writeC = <span class="hljs-function">(<span class="hljs-params">key: <span class="hljs-built_in">string</span></span>) =&gt;</span> (value: <span class="hljs-built_in">string</span>) =&gt; <span class="hljs-function">(<span class="hljs-params">flush: <span class="hljs-built_in">boolean</span></span>) =&gt;</span>
  write(key, value, flush)
</code></pre>
<p>Trivially we can call the function like this:</p>
<pre><code class="lang-ts">writeC(<span class="hljs-string">'key'</span>)(<span class="hljs-string">'value'</span>)(<span class="hljs-literal">true</span>)
</code></pre>
<p>And, if we wanted to do the same with our pipe syntax we could try something like this.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// ❌ Wrong</span>
pipe(<span class="hljs-literal">true</span>, <span class="hljs-string">'value'</span>, <span class="hljs-string">'key'</span>, writeC)
</code></pre>
<p>But unfortunately this doesn't work because pipeline is evaluated from left-to-right; the compiler will complain that <code>true</code> cannot be piped into <code>value</code> and <code>value</code> cannot be piped into <code>key</code>. To make this work, we will need to enforce the order of operations (just like in math), with more pipes!</p>
<pre><code class="lang-ts"><span class="hljs-comment">// ✅ Correct</span>
pipe(<span class="hljs-literal">true</span>, pipe(<span class="hljs-string">'value'</span>, pipe(<span class="hljs-string">'key'</span>, writeC)))
</code></pre>
<p>Now the compiler understands because we force the right side to evaluate first. However, this syntax isn't ideal because its annoying to add additional pipes for the sake of ordering.</p>
<p>The solution to this is <code>ap</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { ap } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Identity'</span>

pipe(writeC, ap(<span class="hljs-string">'key'</span>), ap(<span class="hljs-string">'value'</span>), ap(<span class="hljs-literal">true</span>))
</code></pre>
<p>Remember when I said <code>ap</code> is just piping a function into a value? This is exactly what you see here.</p>
<p><code>writeC</code> is piped into <code>key</code> which forms the function <code>(value: string) =&gt; (flush: boolean) =&gt; write(key, value, flush)</code>. This function is piped into <code>value</code> which forms the function <code>(flush: boolean) =&gt; write(key, value, flush)</code>. And finally, this last function is piped into <code>true</code> which calls our 3 parameter write function: <code>write(key, value, flush)</code>.</p>
<p>In essence, <code>ap</code> just makes it easier to curry function values while keeping the correct order of operations.</p>
<hr />
<p>Another use case for <code>ap</code> is when you have functions and values that don't play well together because one of them is trapped inside an <code>Option</code> or an <code>Either</code>, etc... <code>ap</code> is useful in this scenario because it can lift values or functions into a particular category.</p>
<p>To demonstrate, lets look at an example.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> O <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Option'</span>
<span class="hljs-keyword">import</span> { Option } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Option'</span>

<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> a: Option&lt;<span class="hljs-built_in">number</span>&gt;
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> b: Option&lt;<span class="hljs-built_in">string</span>&gt;
<span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span>(<span class="hljs-params">a: <span class="hljs-built_in">number</span>, b: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">boolean</span></span>
</code></pre>
<p>As you can see, we want to call <code>foo</code> using our variables <code>a</code> and <code>b</code>, but the problem is: <code>a</code> and <code>b</code> are in the Option category while <code>foo</code>
takes plain values.</p>
<p>A naive way of executing <code>foo</code> is to use <code>chain</code> and <code>map</code>.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Option&lt;boolean&gt;</span>
O.option.chain(a, <span class="hljs-function">(<span class="hljs-params">a1</span>) =&gt;</span> O.option.map(b, <span class="hljs-function">(<span class="hljs-params">b1</span>) =&gt;</span> foo(a1, b1)))
</code></pre>
<p>But this is terrible because:</p>
<ol>
<li>We have to awkwardly name our variables with a number suffix because we don't want to shadow the outer variable.</li>
<li>It doesn't scale if we have more parameters.</li>
<li>Its ugly and confusing.</li>
</ol>
<p>Lets try again.</p>
<p>First we need to convert <code>foo</code> into a curried function <code>fooC</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> fooC = <span class="hljs-function">(<span class="hljs-params">a: <span class="hljs-built_in">number</span></span>) =&gt;</span> (b: <span class="hljs-built_in">string</span>) =&gt; foo(a, b)
</code></pre>
<p>Then it is just the same thing as we did before, BUT we need to <em>lift</em> <code>fooC</code> into the <code>Option</code> category using <code>of</code>, because the <code>Option</code> version of <code>ap</code> must operate on two options.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Option&lt;boolean&gt;</span>
pipe(O.of(fooC), O.ap(a), O.ap(b))
</code></pre>
<p>Lets extend the example a bit further. Let say we had another function <code>bar</code> that takes a boolean (the return value of <code>foo</code>) and returns an <code>object</code>. Naturally, we want to call <code>foo</code> and subsequently <code>bar</code> with the return value of <code>foo</code>.</p>
<p>We have already computed <code>foo</code> as an <code>Option&lt;boolean&gt;</code>, so this is nothing more than a simple <em>lift</em> into <code>ap</code></p>
<pre><code class="lang-ts"><span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span>(<span class="hljs-params">a: <span class="hljs-built_in">boolean</span></span>): <span class="hljs-title">object</span>

<span class="hljs-title">const</span> <span class="hljs-title">fooOption</span> = <span class="hljs-title">pipe</span>(<span class="hljs-params">O.<span class="hljs-keyword">of</span>(fooC), O.ap(a), O.ap(b)</span>)

// <span class="hljs-title">Option</span>&lt;<span class="hljs-title">object</span>&gt;
<span class="hljs-title">pipe</span>(<span class="hljs-params">O.<span class="hljs-keyword">of</span>(bar), O.ap(fooOption)</span>)</span>
</code></pre>
<p>Cool, <code>ap</code> is clearly powerful. But what are the problems with <code>ap</code>?</p>
<p>First, its boring to have to curried every function in existence just to use fp.</p>
<p>Second, reversing the order of the input value of a function inside of a pipe from left-to-right to right-to-left breaks the natural <code>flow</code> of operations.</p>
<p>In the real world, there's hardly a usecase for <code>ap</code> because we can leverage sequences instead.[^1]</p>
<h2 id="heading-sequences">Sequences</h2>
<p>So what is a sequence?</p>
<p>In math, we think of a sequence as a sequence of numbers. Similarly, we can apply this to a sequence of Options, a sequence of Eithers, etc...</p>
<p>The most common usecase for a sequence is convert an array of say Options into an Option of an array.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// How?</span>
<span class="hljs-built_in">Array</span>&lt;Option&lt;A&gt;&gt; =&gt; Option&lt;A[]&gt;
</code></pre>
<p>To do this, you need to provide sequence an instance of <code>Applicative</code>. An applicative has 3 methods: <code>of</code>, <code>map</code>, and <code>ap</code>. This applicative defines the type of the objects inside of the collection. For a list of <code>Options</code>, we would provide it with <code>O.option</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> A <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Array'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> O <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Option'</span>

<span class="hljs-keyword">const</span> arr = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>].map(O.of)
A.array.sequence(O.option)(arr) <span class="hljs-comment">// Option&lt;number[]&gt;</span>
</code></pre>
<p>Now we lets go back to the problem: how do we use sequence such that we don't have to write a curried function and use <code>ap</code>?</p>
<p>Enter <code>sequenceT</code>.</p>
<h3 id="heading-sequencet">SequenceT</h3>
<p><code>sequenceT</code> is the same as a regular <code>sequence</code> except you pass it a <a target="_blank" href="/s/org/typescriptlang/www/G.https/docs/handbook/functions.html#rest-parameters" o-href="https://www.typescriptlang.org/docs/handbook/functions.html#rest-parameters">rest parameter</a> (vararg). The return value is the provided applicative with a tuple as the type parameter.</p>
<p>For example:</p>
<pre><code class="lang-ts"><span class="hljs-comment">//  Option&lt;[number, string]&gt;</span>
sequenceT(O.option)(O.of(<span class="hljs-number">123</span>), O.of(<span class="hljs-string">'asdf'</span>))
</code></pre>
<p>Now you see where this is going. We can just pipe this into our original <code>foo</code> and <code>bar</code> functions.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span>(<span class="hljs-params">a: <span class="hljs-built_in">number</span>, b: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">boolean</span>
<span class="hljs-title">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span>(<span class="hljs-params">a: <span class="hljs-built_in">boolean</span></span>): <span class="hljs-title">object</span>

// <span class="hljs-title">Option</span>&lt;<span class="hljs-title">object</span>&gt;
<span class="hljs-title">pipe</span>(<span class="hljs-params">
  sequenceT(O.option)(O.<span class="hljs-keyword">of</span>(<span class="hljs-number">123</span>), O.<span class="hljs-keyword">of</span>(<span class="hljs-string">'asdf'</span>)),
  O.map((args) =&gt; foo(...args)),
  O.map(bar),
</span>)</span></span>
</code></pre>
<p>Note, I had to use the <code>...</code> spread syntax to convert the tuple into parameter form.</p>
<h3 id="heading-sequences-1">SequenceS</h3>
<p>Sometime our function takes a single object parameter rather than multiple arguments. To solve this problem we can leverage <code>sequenceS</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> E <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Either'</span>

<span class="hljs-keyword">type</span> RegisterInput = {
  email: <span class="hljs-built_in">string</span>
  password: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">validateEmail</span>(<span class="hljs-params">email: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">E</span>.<span class="hljs-title">Either</span>&lt;<span class="hljs-title">Error</span>, <span class="hljs-title">string</span>&gt;
<span class="hljs-title">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">validatePassword</span>(<span class="hljs-params">password: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">E</span>.<span class="hljs-title">Either</span>&lt;<span class="hljs-title">Error</span>, <span class="hljs-title">string</span>&gt;
<span class="hljs-title">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params">input: RegisterInput</span>): <span class="hljs-title">unknown</span>

<span class="hljs-title">declare</span> <span class="hljs-title">const</span> <span class="hljs-title">input</span>: <span class="hljs-title">RegisterInput</span>

<span class="hljs-title">pipe</span>(<span class="hljs-params">
  input,
  ({ email, password }) =&gt;
    sequenceS(E.either)({
      email: validateEmail(email),
      password: validatePassword(password),
    }),
  E.map(register),
</span>)</span></span></span>
</code></pre>
<h2 id="heading-traversals">Traversals</h2>
<p>Sometimes your inputs will not line up nicely and you need to perform some additional computations before applying <code>sequence</code>. Traversal is the answer to this. It performs the same thing sequence but lets us transform the intermediate value.</p>
<p>A good example network request to retrieve parts of a file. You either want all the parts or you want none of them.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> TE <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/TaskEither'</span>
<span class="hljs-keyword">import</span> { TaskEither } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/TaskEither'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> A <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Array'</span>

<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> getPartIds: <span class="hljs-function">() =&gt;</span> TaskEither&lt;<span class="hljs-built_in">Error</span>, <span class="hljs-built_in">string</span>[]&gt;
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> getPart: <span class="hljs-function">(<span class="hljs-params">partId: <span class="hljs-built_in">string</span></span>) =&gt;</span> TaskEither&lt;<span class="hljs-built_in">Error</span>, Blob&gt;

<span class="hljs-comment">// ✅ TE.TaskEither&lt;Error, Blob[]&gt;</span>
pipe(getPartIds(), TE.chain(A.traverse(TE.taskEither)(getPart)))
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this post we've learned about Apply, its usecases, and how we can <em>apply</em> it to our lives with sequences and traversals.</p>
<p>Thanks for reading and if you like this content, please give me a follow on <a target="_blank" href="/s/com/twitter/G.https/ryanleecode" o-href="https://twitter.com/ryanleecode">Twitter</a> and shoot me a DM if you have questions!.</p>
<hr />
<p>[^1]: Sequences and traversals use <code>ap</code> internally.</p>
]]></content:encoded></item><item><title><![CDATA[Practical Guide to Fp-ts P4: Arrays, Semigroups, Monoids]]></title><description><![CDATA[⚠️ Disclaimer Warning
  
    fp-ts is now dead. Please use effect-ts instead.
  
  
    Update 2024: effect-ts is the recommended library for functional programming in TypeScript.
  


Introduction
Welcome to the fourth post on learning fp-ts the pra...]]></description><link>https://rlee.dev/practical-guide-to-fp-ts-part-4</link><guid isPermaLink="true">https://rlee.dev/practical-guide-to-fp-ts-part-4</guid><category><![CDATA[Functional Programming]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Mon, 14 Sep 2020 14:54:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1619908586596/7fWsTtJIP.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div>
  <h3>⚠️ Disclaimer Warning</h3>
  <p>
    <strong>fp-ts</strong> is now dead. Please use <a href="/s/website/effect/G.https/" o-href="https://effect.website/" target="_blank"><strong>effect-ts</strong></a> instead.
  </p>
  <p>
    <em>Update 2024: effect-ts is the recommended library for functional programming in TypeScript.</em>
  </p>
</div>

<h2 id="heading-introduction">Introduction</h2>
<p>Welcome to the fourth post on learning fp-ts the practical way. This series is dedicated to learning fp-ts and functional programming with no mathematical knowledge required.</p>
<p>In this post, I'm going to introduce how to use arrays effectively in fp-ts and how we can use <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Semigroup" o-href="https://en.wikipedia.org/wiki/Semigroup">semigroups</a> and <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Monoid" o-href="https://en.wikipedia.org/wiki/Monoid">monoids</a> to easily compose operations over arrays.</p>
<h2 id="heading-array-basics">Array Basics</h2>
<p>The most basic data structure you'll encounter on a daily basis is the Array data type. Arrays are useful to us because we can use them to perform computations by traversing over its elements. But before we jump into traversals with fp-ts, lets start with the basics by going back to loops.</p>
<h3 id="heading-for-loop">For Loop</h3>
<p>The traditional way of traversing over an array is to use a loop with an index variable, <code>i</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]

<span class="hljs-keyword">let</span> sum = <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; foo.length; i++) {
  sum += foo[i]
}
<span class="hljs-built_in">console</span>.log(sum) <span class="hljs-comment">// 6</span>
</code></pre>
<h3 id="heading-for-of-loop">For-of Loop</h3>
<p>Instead of using an index counter, we can also directly iterate over the elements using the <code>for-of</code> syntax.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]

<span class="hljs-keyword">let</span> sum = <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> x <span class="hljs-keyword">of</span> foo) {
  sum += x
}
<span class="hljs-built_in">console</span>.log(sum) <span class="hljs-comment">// 6</span>
</code></pre>
<h3 id="heading-functional-loops">Functional Loops</h3>
<p>But lets be real, all the cool kids these days are using the fancy functional <code>map</code>, <code>reduce</code>, <code>filter</code> syntax.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]

<span class="hljs-keyword">const</span> sum = foo
  .map(<span class="hljs-function">(<span class="hljs-params">x</span>) =&gt;</span> x - <span class="hljs-number">1</span>)
  .filter(<span class="hljs-function">(<span class="hljs-params">x</span>) =&gt;</span> x % <span class="hljs-number">2</span> === <span class="hljs-number">0</span>)
  .reduce(<span class="hljs-function">(<span class="hljs-params">prev, next</span>) =&gt;</span> prev + next, <span class="hljs-number">0</span>)
<span class="hljs-built_in">console</span>.log(sum) <span class="hljs-comment">// 6</span>
</code></pre>
<p>In fp-ts, we can do the same thing but with different syntax.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> A <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Array'</span>
<span class="hljs-keyword">import</span> { pipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/function'</span>

<span class="hljs-keyword">const</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]

<span class="hljs-keyword">const</span> sum = pipe(
  A.array.map(foo, <span class="hljs-function">(<span class="hljs-params">x</span>) =&gt;</span> x - <span class="hljs-number">1</span>),
  A.filter(<span class="hljs-function">(<span class="hljs-params">x</span>) =&gt;</span> x % <span class="hljs-number">2</span> === <span class="hljs-number">0</span>),
  A.reduce(<span class="hljs-number">0</span>, <span class="hljs-function">(<span class="hljs-params">prev, next</span>) =&gt;</span> prev + next),
)
<span class="hljs-built_in">console</span>.log(sum) <span class="hljs-comment">// 6</span>
</code></pre>
<p>However, this just looks like syntactic sugar, so let us digress. Why should you install fp-ts when you can just use the regular array methods?</p>
<h2 id="heading-array-extensions">Array Extensions</h2>
<p>If you come from the Python world, you'll be shocked to find that Typescript doesn't have built in array methods like <a target="_blank" href="/s/org/python/docs/G.https/3.9/library/functions.html#zip" o-href="https://docs.python.org/3.9/library/functions.html#zip"><code>zip</code></a>. You should use fp-ts because it gives you the additional batteries you need to do fancy array manipulation.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> A <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Array'</span>
<span class="hljs-keyword">import</span> { pipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/function'</span>

<span class="hljs-keyword">const</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
<span class="hljs-keyword">const</span> bar = [<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>]

<span class="hljs-keyword">const</span> zipped = pipe(foo, A.zip(bar))
<span class="hljs-built_in">console</span>.log(zipped) <span class="hljs-comment">// [[1, 'a], [2, 'b], [3, 'c']]</span>
</code></pre>
<p>The cool thing about this is that it preserves the type-safety of the elements in the array. The type of <code>zipped</code> is <code>Array&lt;[number, string]&gt;</code> rather than <code>Array&lt;Array&lt;number | string&gt;&gt;</code>. In other words, <code>zipped</code> is an <em>array of <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Tuple" o-href="https://en.wikipedia.org/wiki/Tuple">tuples</a></em>.</p>
<p>If you find this cool, then you might also be interested in the <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Array.ts.html#unzip" o-href="https://gcanti.github.io/fp-ts/modules/Array.ts.html#unzip">unzip</a>, <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Array.ts.html#partition" o-href="https://gcanti.github.io/fp-ts/modules/Array.ts.html#partition">partition</a>, and <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Array.ts.html#flatten" o-href="https://gcanti.github.io/fp-ts/modules/Array.ts.html#flatten">flatten</a> operators.</p>
<h2 id="heading-array-type-safety">Array Type Safety</h2>
<p>One of things that's not type-safe safe in Typescript is array access and mutations. If you're coming from the Java world, then you should know in Typescript, there is no such thing as an <code>IndexOutOfBounds</code> exception. Accessing an element that is out of bounds returns <code>undefined</code>. You can also create undefined behaviour when you mutate an array outside of its bounds.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]

<span class="hljs-keyword">const</span> x: <span class="hljs-built_in">number</span> = foo[<span class="hljs-number">4</span>] <span class="hljs-comment">// no compile error</span>
foo[<span class="hljs-number">5</span>] = <span class="hljs-number">2</span> <span class="hljs-comment">// no runtime error</span>
<span class="hljs-built_in">console</span>.log(foo) <span class="hljs-comment">// [1, 2, 3, undefined, undefined, 2]</span>
</code></pre>
<p>Now just by looking at this code snippet, I can assure you, that we are indeed living in scary times. However, there is light at the end of tunnel; type safe array access is coming in <a target="_blank" href="/s/com/github/G.https/microsoft/TypeScript/issues/40124" o-href="https://github.com/microsoft/TypeScript/issues/40124">Typescript 4.1</a>. The term they use is for it <a target="_blank" href="/s/com/github/G.https/microsoft/TypeScript/pull/39560" o-href="https://github.com/microsoft/TypeScript/pull/39560"><em>pedantic index signatures</em></a>.</p>
<p>In the meantime, in our never ending search for purity, we must look to fp-ts to save us from the gallows of <code>undefined</code>.</p>
<p><img src="/s/com/hashnode/cdn/G.https/res/hashnode/image/upload/v1618066431744/MpTp9a29w.png" o-src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618066431744/MpTp9a29w.png" alt="undefined-goes-brrr" /></p>
<h3 id="heading-lookup">Lookup</h3>
<p>If we want to be type safe when accessing an element in an array, we should use the <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Array.ts.html#lookup" o-href="https://gcanti.github.io/fp-ts/modules/Array.ts.html#lookup">lookup</a> function. It takes two parameters, an index and an array and returns an <code>Option</code> type.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> A <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Array'</span>
<span class="hljs-keyword">import</span> { pipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/function'</span>

pipe([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>], A.lookup(<span class="hljs-number">1</span>)) <span class="hljs-comment">// { _tag: 'Some', value: 2 }</span>
pipe([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>], A.lookup(<span class="hljs-number">3</span>)) <span class="hljs-comment">// { _tag: 'None' }</span>
</code></pre>
<p>Because it returns an Option, we are forced to deal with the possible <code>none</code> case.</p>
<p>However, this can become cumbersome when we are interested in the first element, otherwise known as the head of the array and when we know the array is not empty.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
<span class="hljs-keyword">if</span> (foo.length &gt; <span class="hljs-number">0</span>) {
  <span class="hljs-comment">// We don't want an Option since we know it will always be some</span>
  <span class="hljs-keyword">const</span> firstElement = A.head(foo) <span class="hljs-comment">// { _tag: 'Some', value: 1 }</span>
}
</code></pre>
<p>To deal with this, fp-ts has another type known as the <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/NonEmptyArray.ts.html" o-href="https://gcanti.github.io/fp-ts/modules/NonEmptyArray.ts.html"><code>NonEmptyArray</code></a>. The <code>NonEmptyArray</code> type also has a <code>head</code> operator but it return the underlying value instead of an <code>Option</code>.</p>
<p>Examine the type definition to see the difference.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Array</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> head: &lt;A&gt;<span class="hljs-function">(<span class="hljs-params"><span class="hljs-keyword">as</span>: A[]</span>) =&gt;</span> Option&lt;A&gt;

<span class="hljs-comment">// NonEmptyArray</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> head: &lt;A&gt;<span class="hljs-function">(<span class="hljs-params">nea: NonEmptyArray&lt;A&gt;</span>) =&gt;</span> A
</code></pre>
<p>Now we must answer the question: how do we go from <code>Array&lt;A&gt;</code> 🠂 <code>NonEmptyArray&lt;A&gt;</code>.</p>
<p>In our example, we can do this by replacing our <code>if</code> statement with a <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Array.ts.html#isnonempty" o-href="https://gcanti.github.io/fp-ts/modules/Array.ts.html#isnonempty"><code>isNonEmpty</code></a> guard.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Fp-ts Type guard</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> isNonEmpty: &lt;A&gt;<span class="hljs-function">(<span class="hljs-params"><span class="hljs-keyword">as</span>: A[]</span>) =&gt;</span> <span class="hljs-keyword">as</span> is NonEmptyArray&lt;A&gt;
</code></pre>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> A <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Array'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> NEA <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/NonEmptyArray'</span>

<span class="hljs-keyword">const</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
<span class="hljs-keyword">if</span> (A.isNonEmpty(foo)) {
  <span class="hljs-keyword">const</span> firstElement = NEA.head(foo) <span class="hljs-comment">// 1</span>
}
</code></pre>
<p>Voilà, we have the value instead of an <code>Option</code>.</p>
<p>In short, if you really care about type safety, use lookup to access elements in your array.</p>
<p>Be sure to also checkout the <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Array.ts.html#insertat" o-href="https://gcanti.github.io/fp-ts/modules/Array.ts.html#insertat">insertAt</a> and <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Array.ts.html#updateAt" o-href="https://gcanti.github.io/fp-ts/modules/Array.ts.html#updateAt">updateAt</a> operators.</p>
<hr />
<h2 id="heading-partitioning-non-homogenous-arrays">Partitioning Non-Homogenous Arrays</h2>
<p>In Typescript, we can have two types of arrays: homogenous and non-homogeneous. In a homogenous array, every element must be of the same type. Elements in a non-homogenous arrays can take on union of types.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Homogenous</span>
<span class="hljs-keyword">const</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>] <span class="hljs-comment">// number[]</span>

<span class="hljs-comment">// Non Homogenous</span>
<span class="hljs-keyword">const</span> bar = [<span class="hljs-number">1</span>, <span class="hljs-string">'2'</span>, <span class="hljs-number">3</span>] <span class="hljs-comment">// (string | number)[]</span>
</code></pre>
<p>When we iterate over a non-homogenous array, we are limited by what is common between the union of types.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Foo = {
  <span class="hljs-keyword">readonly</span> _tag: <span class="hljs-string">'Foo'</span>
  <span class="hljs-keyword">readonly</span> f: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">number</span>
}

<span class="hljs-keyword">type</span> Bar = {
  <span class="hljs-keyword">readonly</span> _tag: <span class="hljs-string">'Bar'</span>
  <span class="hljs-keyword">readonly</span> g: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">number</span>
}

<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> arr: <span class="hljs-built_in">Array</span>&lt;Foo | Bar&gt;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> a <span class="hljs-keyword">of</span> arr) {
  <span class="hljs-built_in">console</span>.log(a._tag) <span class="hljs-comment">// Ok</span>
  <span class="hljs-built_in">console</span>.log(a.f()) <span class="hljs-comment">// Error: not assignable to Bar</span>
  <span class="hljs-built_in">console</span>.log(a.g()) <span class="hljs-comment">// Error: not assignable to Foo</span>
}
</code></pre>
<p>But, lets say we had this problem domain. We want to sum all elements belonging to <code>Foo</code> using <code>f()</code> and multiply it by the maximum of all elements belong to <code>Bar</code> using <code>g()</code>.</p>
<p>Trivially, we can compute it imperatively.</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">compute</span>(<span class="hljs-params">arr: <span class="hljs-built_in">Array</span>&lt;Foo | Bar&gt;</span>) </span>{
  <span class="hljs-keyword">let</span> sum = <span class="hljs-number">0</span>
  <span class="hljs-keyword">let</span> max = <span class="hljs-built_in">Number</span>.NEGATIVE_INFINITY

  arr.forEach(<span class="hljs-function">(<span class="hljs-params">a</span>) =&gt;</span> {
    <span class="hljs-keyword">switch</span> (a._tag) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">'Foo'</span>:
        sum += a.f()
        <span class="hljs-keyword">break</span>
      <span class="hljs-keyword">case</span> <span class="hljs-string">'Bar'</span>:
        max = <span class="hljs-built_in">Math</span>.max(max, a.g())
        <span class="hljs-keyword">break</span>
    }
  })

  <span class="hljs-keyword">return</span> sum * max
}
</code></pre>
<p>This is great. It gets the job done. And its not too verbose. How does it look in fp-ts?</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> A <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Array'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> NEA <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/NonEmptyArray'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> O <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Option'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> E <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Either'</span>
<span class="hljs-keyword">import</span> { pipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/function'</span>

<span class="hljs-keyword">const</span> compute = <span class="hljs-function">(<span class="hljs-params">arr: <span class="hljs-built_in">Array</span>&lt;Foo | Bar&gt;</span>) =&gt;</span>
  pipe(
    A.array.partitionMap(arr, <span class="hljs-function">(<span class="hljs-params">a</span>) =&gt;</span>
      a._tag === <span class="hljs-string">'Foo'</span> ? E.left(a) : E.right(a),
    ),
    <span class="hljs-function">(<span class="hljs-params">{ left: foos, right: bars }</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> sum = A.array.reduce(foos, <span class="hljs-number">0</span>, <span class="hljs-function">(<span class="hljs-params">prev, foo</span>) =&gt;</span> prev + foo.f())
      <span class="hljs-keyword">const</span> max = A.array.reduce(bars, <span class="hljs-built_in">Number</span>.NEGATIVE_INFINITY, <span class="hljs-function">(<span class="hljs-params">max, bar</span>) =&gt;</span>
        <span class="hljs-built_in">Math</span>.max(max, bar.g()),
      )

      <span class="hljs-keyword">return</span> sum * max
    },
  )
</code></pre>
<p>You probably think this looks ugly and verbose. And you would be are correct. But however, isn't functional code suppose to be more concise? The problem with this is, we have to write a lot what I called <em>plumbing</em> code to <code>reduce</code> the sum and the max to a single numeric value.</p>
<p>To clean this up, we need to learn about Semigroups and Monoids.</p>
<h2 id="heading-semigroups">Semigroups</h2>
<p>A Semigroup is a type that is able to take two homogenous values and produce a single homogenous value. Semigroups must implement a function known as <code>concat</code>. An example of a concat operation is addition: given two numbers, we can concatenate them together by addition to produce a single number.</p>
<p>The type definition for a Semigroup looks like this.[^1]</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Semigroup&lt;A&gt; {
  <span class="hljs-keyword">readonly</span> concat: <span class="hljs-function">(<span class="hljs-params">x: A, y: A</span>) =&gt;</span> A
}
</code></pre>
<p>This is useful to us because we can use it to generalize the addition operation <code>prev + foo.f()</code> from our reduce function.</p>
<p>Also important to note is, when implementing a Semigroup, we don't need to literally concat both elements x and y, we just need to produce a number. For example you could have a semigroup that always returns one.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> onlyOne: Semigroup&lt;<span class="hljs-built_in">number</span>&gt; = {
  concat: <span class="hljs-function">(<span class="hljs-params">_, _</span>) =&gt;</span> <span class="hljs-number">1</span>,
}
</code></pre>
<p>What this also means is that we can implement a semigroup for finding the max of our <code>bars</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> semigroupMax: Semigroup&lt;<span class="hljs-built_in">number</span>&gt; = {
  concat: <span class="hljs-function">(<span class="hljs-params">x, y</span>) =&gt;</span> <span class="hljs-built_in">Math</span>.max(x, y),
}
</code></pre>
<p>Or more concisely.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> semigroupMax: Semigroup&lt;<span class="hljs-built_in">number</span>&gt; = {
  concat: <span class="hljs-built_in">Math</span>.max,
}
</code></pre>
<p>Going back to our original problem domain, we can see how this paradigm can be useful for sum and maximum operations. However, we have a problem. The function takes two elements. What happens if our input array is empty?</p>
<p>To solve this problem we need to learn about Monoids.</p>
<h2 id="heading-monoids">Monoids</h2>
<p>Monoids are an extension of Semigroup but it also includes the empty or default element.</p>
<p>In fp-ts, this is what the type definition looks like</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Monoid&lt;A&gt; <span class="hljs-keyword">extends</span> Semigroup&lt;A&gt; {
  <span class="hljs-keyword">readonly</span> empty: A
}
</code></pre>
<p>If you go back to the <code>reduce</code> functions we wrote previously, we specified <code>0</code> as the empty element for addition and <code>Number.NEGATIVE_INFINITY</code> for <code>Math.max</code>. We would plug in the same values for a monoid.</p>
<p>For example, we can create a <code>monoidMax</code> by extending <code>semigroupMax</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { Monoid } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Monoid'</span>

<span class="hljs-keyword">const</span> monoidMax: Monoid&lt;<span class="hljs-built_in">number</span>&gt; = {
  concat: semigroupMax.concat,
  empty: <span class="hljs-built_in">Number</span>.NEGATIVE_INFINITY,
}
</code></pre>
<p>Now we can replace our <code>reduce</code> functions with <code>foldMap</code> functions alleviating the responsibility of the reduction to the monoid.[^2]</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { Monoid, monoidSum } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Monoid'</span>

<span class="hljs-keyword">const</span> compute = <span class="hljs-function">(<span class="hljs-params">arr: <span class="hljs-built_in">Array</span>&lt;Foo | Bar&gt;</span>) =&gt;</span>
  pipe(
    A.array.partitionMap(arr, <span class="hljs-function">(<span class="hljs-params">a</span>) =&gt;</span>
      a._tag === <span class="hljs-string">'Foo'</span> ? E.left(a) : E.right(a),
    ),
    <span class="hljs-function">(<span class="hljs-params">{ left: foos, right: bars }</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> sum = A.array.foldMap(monoidSum)(foos, <span class="hljs-function">(<span class="hljs-params">foo</span>) =&gt;</span> foo.f())
      <span class="hljs-keyword">const</span> max = A.array.foldMap(monoidMax)(bars, <span class="hljs-function">(<span class="hljs-params">bar</span>) =&gt;</span> bar.g())

      <span class="hljs-keyword">return</span> sum * max
    },
  )
</code></pre>
<p>Hey, that's nice! Its less verbose and its clear what the function does now. Let's extend our usecase and have a condition where we want to swap the operations. That is, <code>Math.max</code> on <code>foos</code> and <code>sum</code> on <code>bars</code>.</p>
<p>With monoids this is very easy, we can create a <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Higher-order_function" o-href="https://en.wikipedia.org/wiki/Higher-order_function">higher order function</a> and dynamically create the behaviour we want.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> compute = <span class="hljs-function">(<span class="hljs-params">fooMonoid: Monoid&lt;<span class="hljs-built_in">number</span>&gt;, barMonoid: Monoid&lt;<span class="hljs-built_in">number</span>&gt;</span>) =&gt;</span> (
  arr: <span class="hljs-built_in">Array</span>&lt;Foo | Bar&gt;,
) =&gt;
  pipe(
    A.array.partitionMap(arr, <span class="hljs-function">(<span class="hljs-params">a</span>) =&gt;</span>
      a._tag === <span class="hljs-string">'Foo'</span> ? E.left(a) : E.right(a),
    ),
    <span class="hljs-function">(<span class="hljs-params">{ left: foos, right: bars }</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> sum = A.array.foldMap(fooMonoid)(foos, <span class="hljs-function">(<span class="hljs-params">foo</span>) =&gt;</span> foo.f())
      <span class="hljs-keyword">const</span> max = A.array.foldMap(barMonoid)(bars, <span class="hljs-function">(<span class="hljs-params">bar</span>) =&gt;</span> bar.g())

      <span class="hljs-keyword">return</span> sum * max
    },
  )

<span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> i: <span class="hljs-built_in">number</span>
<span class="hljs-keyword">if</span> (i % <span class="hljs-number">2</span> === <span class="hljs-number">0</span>) {
  compute(monoidSum, monoidMax)
} <span class="hljs-keyword">else</span> {
  compute(monoidMax, monoidSum)
}
</code></pre>
<p>Whereas imperatively it might look something like this.</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">compute</span>(<span class="hljs-params">arr: <span class="hljs-built_in">Array</span>&lt;Foo | Bar&gt;, invert: <span class="hljs-built_in">boolean</span></span>) </span>{
  <span class="hljs-keyword">let</span> sum = <span class="hljs-number">0</span>
  <span class="hljs-keyword">let</span> max = <span class="hljs-built_in">Number</span>.NEGATIVE_INFINITY

  arr.forEach(<span class="hljs-function">(<span class="hljs-params">a</span>) =&gt;</span> {
    <span class="hljs-keyword">switch</span> (a._tag) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">'Foo'</span>:
        <span class="hljs-keyword">if</span> (invert) {
          max = <span class="hljs-built_in">Math</span>.max(max, a.f())
        } <span class="hljs-keyword">else</span> {
          sum += a.f()
        }
        <span class="hljs-keyword">break</span>
      <span class="hljs-keyword">case</span> <span class="hljs-string">'Bar'</span>:
        <span class="hljs-keyword">if</span> (invert) {
          sum += a.g()
        } <span class="hljs-keyword">else</span> {
          max = <span class="hljs-built_in">Math</span>.max(max, a.g())
        }
        <span class="hljs-keyword">break</span>
    }
  })

  <span class="hljs-keyword">return</span> sum * max
}
</code></pre>
<p>From this you can understand, the imperative approach gets much worse as the <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Cyclomatic_complexity#:~:text=Cyclomatic%20complexity%20is%20a%20software,in%201976." o-href="https://en.wikipedia.org/wiki/Cyclomatic_complexity#:~:text=Cyclomatic%20complexity%20is%20a%20software,in%201976.">cyclomatic complexity</a> increases. Whereas in functional programming, because it so composable, allows use to easily change behaviours of our program without creating additional complexity in the code.</p>
<p>That's all for this post. As always, if you like this kind of content, please give me a follow on <a target="_blank" href="/s/com/twitter/G.https/ryanleecode" o-href="https://twitter.com/ryanleecode">Twitter</a> and send me a DM or email for what you want to see next!</p>
<hr />
<p>[^1]: Actually Semigroup inherits from Magma which is generalization of Semigroup. The difference Semigroups operations are <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Associative_property" o-href="https://en.wikipedia.org/wiki/Associative_property">associative</a>. See the fp-ts definitions for <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Semigroup.ts.html#semigroup-interface" o-href="https://gcanti.github.io/fp-ts/modules/Semigroup.ts.html#semigroup-interface">Semigroup</a> and <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Magma.ts.html" o-href="https://gcanti.github.io/fp-ts/modules/Magma.ts.html">Magma</a>.</p>
<p>[^2]: Note I imported <code>monoidSum</code> which is just a monoid for addition.</p>
]]></content:encoded></item><item><title><![CDATA[Practical Guide to Fp-ts P3: Task, Either, TaskEither]]></title><description><![CDATA[⚠️ Disclaimer Warning
  
    fp-ts is now dead. Please use effect-ts instead.
  
  
    Update 2024: effect-ts is the recommended library for functional programming in TypeScript.
  


Introduction
This is the third post in my series on learning fp-t...]]></description><link>https://rlee.dev/practical-guide-to-fp-ts-part-3</link><guid isPermaLink="true">https://rlee.dev/practical-guide-to-fp-ts-part-3</guid><category><![CDATA[Functional Programming]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Thu, 16 Jul 2020 14:49:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1618066107009/JDQu_zahc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div>
  <h3>⚠️ Disclaimer Warning</h3>
  <p>
    <strong>fp-ts</strong> is now dead. Please use <a href="/s/website/effect/G.https/" o-href="https://effect.website/" target="_blank"><strong>effect-ts</strong></a> instead.
  </p>
  <p>
    <em>Update 2024: effect-ts is the recommended library for functional programming in TypeScript.</em>
  </p>
</div>

<h2 id="heading-introduction">Introduction</h2>
<p>This is the third post in my series on learning fp-ts the practical way. In my last post, I introduced the <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Option.ts.html" o-href="https://gcanti.github.io/fp-ts/modules/Option.ts.html">Option</a> type and the <code>map</code>, <code>flatten</code>, and <code>chain</code> operators.</p>
<p>This post will introduce two concepts in fp-ts: asynchronous tasks and error handling. Namely we will look at the <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Task.ts.html" o-href="https://gcanti.github.io/fp-ts/modules/Task.ts.html">Task</a>, <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Either.ts.html" o-href="https://gcanti.github.io/fp-ts/modules/Either.ts.html">Either</a>, and <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/TaskEither.ts.html" o-href="https://gcanti.github.io/fp-ts/modules/TaskEither.ts.html">TaskEither</a> types.</p>
<h2 id="heading-task">Task</h2>
<p><img src="/s/com/hashnode/cdn/G.https/res/hashnode/image/upload/v1618066132032/CJD2xkgpB.png" o-src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618066132032/CJD2xkgpB.png" alt="Task-Promise" /></p>
<p>Every asynchronous operation in modern Typescript is done using a <a target="_blank" href="/s/org/mozilla/developer/G.https/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" o-href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a> object. A task is a function that returns a promise which is <strong>expected</strong> to <strong>never</strong> be rejected.</p>
<p>The <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Task.ts.html" o-href="https://gcanti.github.io/fp-ts/modules/Task.ts.html">type definition</a> for task can be found below.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> Task&lt;A&gt; {
  (): <span class="hljs-built_in">Promise</span>&lt;A&gt;
}
</code></pre>
<p>Another way to define task is using a function type definition.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Task&lt;A&gt; = <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">Promise</span>&lt;A&gt;
</code></pre>
<p>Tasks are expected to always succeed but can fail when an error occurs outside our expectations. In this case, the error is thrown and breaks the functional pipeline. An analogy to this is <code>awaiting</code> a Promise that throws an error without putting a <code>try-catch-finally</code> block in front. Test your assumptions before using Task.</p>
<h3 id="heading-why-use-tasks">Why use Tasks?</h3>
<p>A Task is more than a glorified promise; it is also an <strong>expression of intent</strong>.</p>
<p>From a client perspective, when you are using a library, all asynchronous functions will have a type definition that returns a <code>Promise&lt;T&gt;</code>. Some of the functions might never fail but are asynchronous out of necessity. A Promise provides no indication about whether the function can fail. As such, in the imperative model, you are forced to handle these errors using a <code>try-catch-finally</code> block.</p>
<p>By using <code>Task&lt;T&gt;</code>, we relieve the burden on the client to handle errors that don't exist.</p>
<h3 id="heading-when-can-an-operation-never-fail">When can an operation "never fail"?</h3>
<p>In the age of distributed computing, errors are the norm. Languages like Go and Rust embrace this model by <a target="_blank" href="/s/org/rust-lang/doc/G.https/book/ch09-00-error-handling.html" o-href="https://doc.rust-lang.org/book/ch09-00-error-handling.html">forcing you to handle errors</a>. To understand when an operation can never fail, we must first understand the most common ways a function can fail in the first place.</p>
<p>Functions commonly fail because of invalid preconditions. Take the function below, where the precondition is the length of <code>id</code> must be less than or equal to 36.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">someTask</span>(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) </span>{
  <span class="hljs-keyword">if</span> (id.length &gt; <span class="hljs-number">36</span>) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'id must have length less than or equal to 36'</span>)
  }

  <span class="hljs-comment">// do async work here</span>
}
</code></pre>
<p>If we knew the exact implementation of the function and we knew all errors stem from pre-condition failing, then we can assume the function will never fail if and only if we know the length of <code>id</code> is <code>&lt;=</code> 36. As such, we can wrap the function into a Task and argue it never fails.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> id = <span class="hljs-string">'abc'</span>
<span class="hljs-keyword">const</span> task: T.Task&lt;<span class="hljs-built_in">void</span>&gt; = <span class="hljs-function">() =&gt;</span> someTask(id)
</code></pre>
<p>In general, we don't make these assumptions because we don't always know the implementation. It's also <em>risky</em> because the implementation can change without us knowing.</p>
<h3 id="heading-handled-failures-cant-fail">Handled Failures Can't Fail</h3>
<p>A more real-world example is when you have an operation that can fail, but is handled by reducing both the success and failure outcomes into a single type. Since the error has been handled, the function, although asynchronous, will always return a <code>Promise</code> that is fulfilled.</p>
<p>Take this function that reduces both the success and failure outcomes into a boolean result.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">boolTask</span>(<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">boolean</span>&gt; </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> asyncFunction()
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
  }
}
</code></pre>
<p>By definition, this function already implements the <code>Task</code> interface, but because the return type is a <code>Promise</code>, the result is still ambiguous to the client. We can remove the ambiguity by adjusting the syntax.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { Task } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Task'</span>

<span class="hljs-keyword">const</span> boolTask: Task&lt;<span class="hljs-built_in">boolean</span>&gt; = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> asyncFunction()
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
  }
}
</code></pre>
<h3 id="heading-constructors">Constructors</h3>
<p>Any arbitrary value can become a Task by using the <code>of</code> operator to lift it into the <code>Task</code> world. This is equivalent to calling <code>Promise.resolve</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> T <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Task'</span>

<span class="hljs-keyword">const</span> foo = <span class="hljs-string">'asdf'</span> <span class="hljs-comment">// string</span>
<span class="hljs-keyword">const</span> bar = T.of(foo) <span class="hljs-comment">// T.Task&lt;string&gt;</span>

<span class="hljs-comment">// Same As</span>
<span class="hljs-keyword">const</span> fdsa: T.Task&lt;<span class="hljs-built_in">string</span>&gt; = <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">Promise</span>.resolve(foo)
</code></pre>
<h2 id="heading-either">Either</h2>
<p>An Either is a type that represents a <em>synchronous</em> operation that can succeed or fail. Much like Option, where it is <code>Some</code> or <code>None</code>, the Either type is either <code>Right</code> or <code>Left</code>. <code>Right</code> represents success and <code>Left</code> represents failure. It is analogous to the <a target="_blank" href="/s/org/rust-lang/doc/G.https/std/result/" o-href="https://doc.rust-lang.org/std/result/">Result</a> type in Rust.</p>
<p>As such, we get the following type definitions.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Either&lt;E, A&gt; = Left&lt;E&gt; | Right&lt;A&gt;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Left&lt;E&gt; {
  <span class="hljs-keyword">readonly</span> _tag: <span class="hljs-string">'Left'</span>
  <span class="hljs-keyword">readonly</span> left: E
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Right&lt;A&gt; {
  <span class="hljs-keyword">readonly</span> _tag: <span class="hljs-string">'Right'</span>
  <span class="hljs-keyword">readonly</span> right: A
}
</code></pre>
<p>The Either type is a union type of <code>Left</code> and <code>Right</code>. The <code>_tag</code> field is used as a <a target="_blank" href="/s/org/typescriptlang/www/G.https/docs/handbook/advanced-types.html#discriminated-unions" o-href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions">discriminator</a> to differentiate between <code>Left</code> and <code>Right</code>.</p>
<h3 id="heading-why-use-eithers">Why use Eithers</h3>
<p>Eithers are essential for capturing error states in functional programming. We need the Eithers because we cannot break pipelines by throwing errors. Error states must either be handled or propagated up the call stack.</p>
<p>Eithers are also advantageous to their <code>try-catch-finally</code> counterparts because the error is always type-safe. When you use a <code>catch</code> block, the <a target="_blank" href="/s/com/microsoft/devblogs/G.https/typescript/announcing-typescript-4-0-beta/#unknown-on-catch" o-href="https://devblogs.microsoft.com/typescript/announcing-typescript-4-0-beta/#unknown-on-catch">error is always of type <code>unknown</code></a>. This is inconvenient for you as the client because you need to use <code>instanceof</code> to narrow down the error type. Even worse is when you are forced to define your own <a target="_blank" href="/s/org/typescriptlang/www/G.https/docs/handbook/advanced-types.html#type-guards-and-differentiating-types" o-href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types">custom type guards</a> to do the same thing.</p>
<p>With Eithers, we know every possible error state based on the type signature. We can choose to handle them in a switch statement or continue to propagate up the call stack.</p>
<h3 id="heading-eithers-in-action">Eithers in Action</h3>
<p>Let’s contrive an example where we are validating a password for security. The password must be at least 8 characters long and have at least 1 capital letter. If the password is valid, we will hash it using a very insecure <code>md5</code> hash.</p>
<ol>
<li>Create 2 error classes to represent the two different error states. Join them together into a discriminated union.</li>
</ol>
<pre><code class="lang-ts"><span class="hljs-comment">// password.ts</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> MinLengthValidationError <span class="hljs-keyword">extends</span> <span class="hljs-built_in">Error</span> {
  <span class="hljs-keyword">public</span> _tag: <span class="hljs-string">'PasswordMinLengthValidationError'</span>

  <span class="hljs-keyword">public</span> minLength: <span class="hljs-built_in">number</span>

  <span class="hljs-keyword">private</span> <span class="hljs-keyword">constructor</span>(<span class="hljs-params">minLength: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">super</span>(<span class="hljs-string">'password fails to meet min length requirement: ${minLength}'</span>)
    <span class="hljs-built_in">this</span>._tag = <span class="hljs-string">'PasswordMinLengthValidationError'</span>
    <span class="hljs-built_in">this</span>.minLength = minLength
  }

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">of</span>(minLength: <span class="hljs-built_in">number</span>): MinLengthValidationError {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> MinLengthValidationError(minLength)
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CapitalLetterMissingValidationError <span class="hljs-keyword">extends</span> <span class="hljs-built_in">Error</span> {
  <span class="hljs-keyword">public</span> _tag: <span class="hljs-string">'PasswordCapitalLetterMissingValidationError'</span>

  <span class="hljs-keyword">private</span> <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-built_in">super</span>(<span class="hljs-string">`password is missing a capital letter`</span>)
    <span class="hljs-built_in">this</span>._tag = <span class="hljs-string">'PasswordCapitalLetterMissingValidationError'</span>
  }

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">of</span>(): CapitalLetterMissingValidationError {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> CapitalLetterMissingValidationError()
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> PasswordValidationError =
  | MinLengthValidationError
  | CapitalLetterMissingValidationError
</code></pre>
<p>Note we are using the <code>Error</code> class instead of declaring the error as a plain object because it comes with built-in stack-trace, which is necessary for debugging.</p>
<ol start="2">
<li>Declare the Password Type</li>
</ol>
<pre><code class="lang-ts"><span class="hljs-comment">// password.ts</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Password {
  _tag: <span class="hljs-string">'Password'</span>
  value: <span class="hljs-built_in">string</span>
  isHashed: <span class="hljs-built_in">boolean</span>
}
</code></pre>
<ol start="3">
<li>Create the constructors for the Password Type</li>
</ol>
<pre><code class="lang-ts"><span class="hljs-comment">// password.ts</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">of</span>(<span class="hljs-params">value: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">Password</span> </span>{
  <span class="hljs-keyword">return</span> { _tag: <span class="hljs-string">'Password'</span>, value, isHashed: <span class="hljs-literal">false</span> }
}

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fromHashed</span>(<span class="hljs-params">value: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">Password</span> </span>{
  <span class="hljs-keyword">return</span> { _tag: <span class="hljs-string">'Password'</span>, value, isHashed: <span class="hljs-literal">true</span> }
}
</code></pre>
<ol start="4">
<li>Validate the password using a Password specification.</li>
</ol>
<pre><code class="lang-ts"><span class="hljs-comment">// password.ts</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> PasswordSpecification = {
  minLength?: <span class="hljs-built_in">number</span>
  capitalLetterRequired?: <span class="hljs-built_in">boolean</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">validate</span>(<span class="hljs-params">{
  minLength = 0,
  capitalLetterRequired = <span class="hljs-literal">false</span>,
}: PasswordSpecification = {}</span>) </span>{
  <span class="hljs-keyword">return</span> (password: Password): E.Either&lt;PasswordValidationError, Password&gt; =&gt; {
    <span class="hljs-keyword">if</span> (password.value.length &lt; minLength) {
      <span class="hljs-keyword">return</span> E.left(MinLengthValidationError.of(minLength))
    }

    <span class="hljs-keyword">if</span> (capitalLetterRequired &amp;&amp; !<span class="hljs-regexp">/[A-Z]/</span>.test(password.value)) {
      <span class="hljs-keyword">return</span> E.left(CapitalLetterMissingValidationError.of())
    }

    <span class="hljs-keyword">return</span> E.right({ ...password, isValidated: <span class="hljs-literal">true</span> })
  }
}
</code></pre>
<p>Notice how <code>validate</code> doesn't return a Password type directly, but a function that returns a Password type. We could have put the <code>PasswordSpecification</code> and Password as parameters to a single function, but the reason why we want to separate them is to make function chaining easier.</p>
<p>When we construct the Password using <code>of</code> or <code>fromHashed</code>, we want to directly pipe the result of that function, <code>Password</code>, into the next function. If our <code>validate</code> function were to take two parameters instead of one, it would break the whole flow. This methodology of splitting function parameters is called <a target="_blank" href="/s/info/javascript/G.https/currying-partials" o-href="https://javascript.info/currying-partials">currying</a>.</p>
<p>You may also notice we can only propagate a single error upwards. But what if multiple validations fail? It would be better to propagate all of them. We will learn about this in the next post.</p>
<ol start="5">
<li>Define a hash function that takes a curried hash function.</li>
</ol>
<pre><code class="lang-ts"><span class="hljs-comment">// password.ts</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> HashFn = <span class="hljs-function">(<span class="hljs-params">value: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">string</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hash</span>(<span class="hljs-params">hashFn: HashFn</span>) </span>{
  <span class="hljs-keyword">return</span> (password: Password): <span class="hljs-function"><span class="hljs-params">Password</span> =&gt;</span> ({
    ...password,
    value: hashFn(password.value),
    isHashed: <span class="hljs-literal">true</span>,
  })
}
</code></pre>
<ol start="6">
<li>Create a pipeline</li>
</ol>
<pre><code class="lang-ts"><span class="hljs-comment">// index.ts</span>

<span class="hljs-keyword">import</span> { flow, identity, pipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/function'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Password <span class="hljs-keyword">from</span> <span class="hljs-string">'./password'</span>
<span class="hljs-keyword">import</span> crypto <span class="hljs-keyword">from</span> <span class="hljs-string">'crypto'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> E <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/Either'</span>

<span class="hljs-keyword">const</span> pipeline = flow(
  Password.of,
  Password.validate({ minLength: <span class="hljs-number">8</span>, capitalLetterRequired: <span class="hljs-literal">true</span> }),
  E.map(
    Password.hash(<span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span>
      crypto.createHash(<span class="hljs-string">'md5'</span>).update(value).digest(<span class="hljs-string">'hex'</span>),
    ),
  ),
)
</code></pre>
<ol start="7">
<li>Test using an invalid password</li>
</ol>
<pre><code class="lang-ts"><span class="hljs-built_in">console</span>.log(pipe(<span class="hljs-string">'pw123'</span>, pipeline))
</code></pre>
<p>Produces the following:</p>
<pre><code class="lang-ts">{
  _tag: <span class="hljs-string">'Left'</span>,
  left: <span class="hljs-built_in">Error</span>: password fails to meet min length requirement: <span class="hljs-number">8</span>
      at <span class="hljs-keyword">new</span> MinLengthValidationError (<span class="hljs-regexp">/tmp/</span>either-demo/password.ts:<span class="hljs-number">9</span>:<span class="hljs-number">5</span>)
      at <span class="hljs-built_in">Function</span>.MinLengthValidationError.of (<span class="hljs-regexp">/tmp/</span>either-demo/password.ts:<span class="hljs-number">15</span>:<span class="hljs-number">12</span>)
      at /tmp/either-demo/password.ts:<span class="hljs-number">61</span>:<span class="hljs-number">46</span>
      at /tmp/either-demo/node_modules/fp-ts/lib/<span class="hljs-keyword">function</span>.js:<span class="hljs-number">92</span>:<span class="hljs-number">27</span>
      at <span class="hljs-built_in">Object</span>.pipe (<span class="hljs-regexp">/tmp/</span>either-demo/node_modules/fp-ts/lib/<span class="hljs-keyword">function</span>.js:<span class="hljs-number">190</span>:<span class="hljs-number">20</span>)
      at <span class="hljs-built_in">Object</span>.&lt;anonymous&gt; (<span class="hljs-regexp">/tmp/</span>either-demo/index.ts:<span class="hljs-number">16</span>:<span class="hljs-number">13</span>)
      at Module._compile (internal/modules/cjs/loader.js:<span class="hljs-number">1118</span>:<span class="hljs-number">30</span>)
      at Module.m._compile (<span class="hljs-regexp">/tmp/</span>either-demo/node_modules/ts-node/src/index.ts:<span class="hljs-number">858</span>:<span class="hljs-number">23</span>)
      at Module._extensions..js (internal/modules/cjs/loader.js:<span class="hljs-number">1138</span>:<span class="hljs-number">10</span>)
      at <span class="hljs-built_in">Object</span>.require.extensions.&lt;computed&gt; [<span class="hljs-keyword">as</span> .ts] (<span class="hljs-regexp">/tmp/</span>either-demo/node_modules/ts-node/src/index.ts:<span class="hljs-number">861</span>:<span class="hljs-number">12</span>) {
    _tag: <span class="hljs-string">'PasswordMinLengthValidationError'</span>,
    minLength: <span class="hljs-number">8</span>
  }
}
</code></pre>
<p>Due to the way Node prints errors, <code>left</code> doesn't look like a regular
typescript object. The underlying object looks like this.</p>
<pre><code class="lang-ts">{
  _tag: <span class="hljs-string">'Left'</span>,
  left: {
    message: <span class="hljs-string">'password fails to meet min length requirement: 8'</span>,
    stack: <span class="hljs-string">`Error: password fails to meet min length requirement: 8
      at new MinLengthValidationError (/tmp/either-demo/password.ts:9:5)
      at Function.MinLengthValidationError.of (/tmp/either-demo/password.ts:15:12)
      at /tmp/either-demo/password.ts:61:46
      at /tmp/either-demo/node_modules/fp-ts/lib/function.js:92:27
      at Object.pipe (/tmp/either-demo/node_modules/fp-ts/lib/function.js:190:20)
      at Object.&lt;anonymous&gt; (/tmp/either-demo/index.ts:16:13)
      at Module._compile (internal/modules/cjs/loader.js:1118:30)
      at Module.m._compile (/tmp/either-demo/node_modules/ts-node/src/index.ts:858:23)
      at Module._extensions..js (internal/modules/cjs/loader.js:1138:10)
      at Object.require.extensions.&lt;computed&gt; [as .ts] (/tmp/either-demo/node_modules/ts-node/src/index.ts:861:12)`</span>
    _tag: <span class="hljs-string">'PasswordMinLengthValidationError'</span>,
    minLength: <span class="hljs-number">8</span>
  }
}
</code></pre>
<ol start="8">
<li>Test using a valid password.</li>
</ol>
<pre><code class="lang-ts"><span class="hljs-built_in">console</span>.log(pipe(<span class="hljs-string">'Password123'</span>, pipeline))
</code></pre>
<p>Produces the following:</p>
<pre><code class="lang-ts">{
  _tag: <span class="hljs-string">'Right'</span>,
  right: {
    _tag: <span class="hljs-string">'Password'</span>,
    value: <span class="hljs-string">'42f749ade7f9e195bf475f37a44cafcb'</span>,
    isHashed: <span class="hljs-literal">true</span>,
    isValidated: <span class="hljs-literal">true</span>
  }
}
</code></pre>
<h3 id="heading-chaining-eithers">Chaining Eithers</h3>
<p>What if <code>hash</code> was an operation that could also fail and return an <code>Either</code>? We can <code>chainW</code> operator to chain both <code>validate</code> and <code>hash</code> into a single Either type. We'll use the base <code>Error</code> type to represent this error for simplicity's sake.</p>
<ol>
<li>Update the hash function to return an Either</li>
</ol>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> HashFn = <span class="hljs-function">(<span class="hljs-params">value: <span class="hljs-built_in">string</span></span>) =&gt;</span> E.Either&lt;<span class="hljs-built_in">Error</span>, <span class="hljs-built_in">string</span>&gt;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hash</span>(<span class="hljs-params">hashFn: HashFn</span>) </span>{
  <span class="hljs-keyword">return</span> (password: Password): E.Either&lt;<span class="hljs-built_in">Error</span>, Password&gt; =&gt;
    pipe(
      hashFn(password.value),
      E.map(<span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> ({
        ...password,
        value,
        isHashed: <span class="hljs-literal">true</span>,
      })),
    )
}
</code></pre>
<ol start="2">
<li>Update the pipeline using <code>chainW</code></li>
</ol>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> pipeline = flow(
  Password.of,
  Password.validate({ minLength: <span class="hljs-number">8</span>, capitalLetterRequired: <span class="hljs-literal">true</span> }),
  E.chainW(
    Password.hash(<span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span>
      E.right(crypto.createHash(<span class="hljs-string">'md5'</span>).update(value).digest(<span class="hljs-string">'hex'</span>)),
    ),
  ),
)
</code></pre>
<p>The reason why we use <code>chainW</code> instead of <code>chain</code> because we want to widen the final type to include both errors from <code>validate</code> and <code>hash</code>. If you hover over <code>pipeline</code> to inspect the type, this is what you would get.</p>
<pre><code class="lang-ts">E.Either&lt;
  MinLengthValidationError | CapitalLetterMissingValidationError | <span class="hljs-built_in">Error</span>,
  Password
&gt;
</code></pre>
<p>But if we swap <code>chainW</code> with <code>chain</code>, we would only get the final error type in the chain.</p>
<pre><code class="lang-ts">E.Either&lt;<span class="hljs-built_in">Error</span>, Password.Password&gt;
</code></pre>
<p>But note, <code>chain</code> only works here because <code>Error</code> is a superclass of all 3 of our errors. If the left side of the generic to the function <code>hash</code> was not an Error, we would be forced to use <code>chainW</code> to cover the two Errors from <code>validate</code>.</p>
<p>You can run the source code <a target="_blank" href="/s/it/repl/G.https/@ryanleecode/EitherExample" o-href="https://repl.it/@ryanleecode/EitherExample">here</a>.</p>
<h2 id="heading-taskeither">TaskEither</h2>
<p>We know a Task is an asynchronous operation that can't fail. We also know an Either is a synchronous operation that can fail. Putting the two together, a TaskEither is an <strong>asynchronous</strong> operation that <strong>can fail</strong>.</p>
<p>Performing an HTTP request is a good demonstration of this functionality.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>
<span class="hljs-keyword">import</span> { pipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/function'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> TE <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/TaskEither'</span>
;(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> ok = <span class="hljs-keyword">await</span> pipe(
    TE.tryCatch(
      <span class="hljs-function">() =&gt;</span> axios.get(<span class="hljs-string">'https://httpstat.us/200'</span>),
      <span class="hljs-function">(<span class="hljs-params">reason</span>) =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`<span class="hljs-subst">${reason}</span>`</span>),
    ),
    TE.map(<span class="hljs-function">(<span class="hljs-params">resp</span>) =&gt;</span> resp.data),
  )()

  <span class="hljs-built_in">console</span>.log(ok)
  <span class="hljs-comment">// { _tag: 'Right', right: { code: 200, description: 'OK' } }</span>
})()
</code></pre>
<p>Here we are making an http request using axios to <code>httpstat</code> which returns status code <code>200</code>. An error will not occur because the http response is 200 –⁠ Ok. The right side gets printed out.</p>
<p>We can do the same thing for a <code>500</code> status code.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Resp = { code: <span class="hljs-built_in">number</span>; description: <span class="hljs-built_in">string</span> }
;(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> pipe(
    TE.tryCatch(
      <span class="hljs-function">() =&gt;</span> axios.get(<span class="hljs-string">'https://httpstat.us/500'</span>),
      <span class="hljs-function">(<span class="hljs-params">reason</span>) =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`<span class="hljs-subst">${reason}</span>`</span>),
    ),
    TE.map(<span class="hljs-function">(<span class="hljs-params">resp</span>) =&gt;</span> resp.data),
  )()

  <span class="hljs-built_in">console</span>.log(result)
  <span class="hljs-comment">/**
   * {
   *   _tag: 'Left',
   *   left: Error: Error: Request failed with status code 500
   *       at /tmp/either-demo/taskeither.ts:19:19
   *       at /tmp/either-demo/node_modules/fp-ts/lib/TaskEither.js:94:85
   *       at processTicksAndRejections (internal/process/task_queues.js:97:5)
   * }
   */</span>
})()
</code></pre>
<h2 id="heading-folding">Folding</h2>
<p>If we're hitting the <code>https://httpstat.us/200</code> endpoint, we can assume the operation will succeed and use the <code>fold</code> operator to convert the output into a <code>Task</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { absurd, constVoid, pipe, unsafeCoerce } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/function'</span>

<span class="hljs-keyword">const</span> result = pipe(
  TE.tryCatch(
    <span class="hljs-function">() =&gt;</span> axios.get(<span class="hljs-string">'https://httpstat.us/200'</span>),
    <span class="hljs-function">() =&gt;</span> constVoid() <span class="hljs-keyword">as</span> <span class="hljs-built_in">never</span>,
  ),
  TE.map(<span class="hljs-function">(<span class="hljs-params">resp</span>) =&gt;</span> unsafeCoerce&lt;unknown, Resp&gt;(resp.data)),
  TE.fold(absurd, T.of),
) <span class="hljs-comment">// Not executing the promise</span>

<span class="hljs-comment">// Result is of type:</span>
<span class="hljs-comment">// T.Task&lt;Resp&gt;</span>
</code></pre>
<p>Notice how I'm passing <code>T.of</code> directly instead of creating an anonymous function that calls <code>T.of</code>. i.e. <code>(a) =&gt; T.of(a)</code>.</p>
<p>Absurd is a function that takes a <code>never</code> and casts it to a generic type <code>A</code>, which in this case is <code>Resp</code>.</p>
<h2 id="heading-asynchronously-error-handling">Asynchronously Error Handling</h2>
<p>Sometimes your error handling is also asynchronous and this is common if you're doing a <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Two-phase_commit_protocol" o-href="https://en.wikipedia.org/wiki/Two-phase_commit_protocol">2 Phase Commit</a>. A good example is when you are processing a database transaction.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { pipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/function'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> TE <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/TaskEither'</span>

<span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">begin</span>(<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt;
<span class="hljs-title">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">commit</span>(<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt;
<span class="hljs-title">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rollback</span>(<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt;

<span class="hljs-title">const</span> <span class="hljs-title">result</span> = <span class="hljs-title">pipe</span>(<span class="hljs-params">
  TE.tryCatch(
    () =&gt; begin(),
    (err) =&gt; <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(`begin txn failed: ${err}`),
  ),
  TE.chain(() =&gt;
    TE.tryCatch(
      () =&gt; commit(),
      (err) =&gt; <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(`commit txn failed: ${err}`),
    ),
  ),
  TE.orElse((originalError) =&gt;
    pipe(
      TE.tryCatch(
        () =&gt; rollback(),
        (err) =&gt; <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(`rollback txn failed: ${err}`),
      ),
      TE.fold(TE.left, () =&gt; TE.left(originalError)),
    ),
  ),
</span>)</span></span></span>
</code></pre>
<p>In this example, we try to rollback if the begin or commit operations fail and return the original error. If rollback also fails, we return the rollback error.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Error handling and asynchronous operations are core components of any application. By understanding Task, Either, and TaskEither, you now have the building blocks you need to develop a simple application.</p>
<p>If you found this post helpful, be sure to also follow me on <a target="_blank" href="/s/com/twitter/G.https/ryanleecode" o-href="https://twitter.com/ryanleecode">Twitter</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Practical Guide to Fp-ts P2: Option, Map, Flatten, Chain]]></title><description><![CDATA[⚠️ Disclaimer Warning
  
    fp-ts is now dead. Please use effect-ts instead.
  
  
    Update 2024: effect-ts is the recommended library for functional programming in TypeScript.
  


Introduction
This is the second post in my series on learning fp-...]]></description><link>https://rlee.dev/practical-guide-to-fp-ts-part-2</link><guid isPermaLink="true">https://rlee.dev/practical-guide-to-fp-ts-part-2</guid><category><![CDATA[Functional Programming]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Thu, 18 Jun 2020 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1618065741561/q_EnaP39T.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div>
  <h3>⚠️ Disclaimer Warning</h3>
  <p>
    <strong>fp-ts</strong> is now dead. Please use <a href="/s/website/effect/G.https/" o-href="https://effect.website/" target="_blank"><strong>effect-ts</strong></a> instead.
  </p>
  <p>
    <em>Update 2024: effect-ts is the recommended library for functional programming in TypeScript.</em>
  </p>
</div>

<h2 id="heading-introduction">Introduction</h2>
<p>This is the second post in my series on learning fp-ts the practical way. In my first post, I introduced the building blocks of fp-ts: <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/function.ts.html#pipe" o-href="https://gcanti.github.io/fp-ts/modules/function.ts.html#pipe">pipe</a> and <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/function.ts.html#flow" o-href="https://gcanti.github.io/fp-ts/modules/function.ts.html#flow">flow</a>. In this post, I will introduce the <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Option.ts.html" o-href="https://gcanti.github.io/fp-ts/modules/Option.ts.html">Option</a> type.</p>
<h2 id="heading-options">Options</h2>
<p>Options are containers that wrap values that could be either <code>undefined</code> or <code>null</code>. If the value exists, we say the Option is of the <code>Some</code> type. If the value is <code>undefined</code> or <code>null</code>, we say it has the <code>None</code> type.</p>
<p>In fp-ts, the Option type is a discriminated union of <code>None</code> and <code>Some</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Option&lt;A&gt; = None | Some&lt;A&gt;
</code></pre>
<p>Why should we use Option types in the first place? Typescript already has good ways to deal with <code>undefined</code> or <code>null</code> values. For example, we can use <a target="_blank" href="/s/org/typescriptlang/www/G.https/docs/handbook/release-notes/typescript-3-7.html#optional-chaining" o-href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining">optional chaining</a> or <a target="_blank" href="/s/org/typescriptlang/www/G.https/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing" o-href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing">nullish coalescing</a>.</p>
<p>Option types are useful because it gives us superpowers. The first superpower is the <code>map</code> operator.</p>
<h2 id="heading-map">Map</h2>
<p>The map operator allows you to transform or intuitively <em>map</em> one value to another. Here is an example of a map function using the <code>pipe</code> operator and an anonymous function.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> foo = {
  bar: <span class="hljs-string">'hello'</span>,
}

pipe(foo, <span class="hljs-function">(<span class="hljs-params">f</span>) =&gt;</span> f.bar) <span class="hljs-comment">// hello</span>
</code></pre>
<p>In this example, <code>foo</code> is mapped to <code>foo.bar</code> and we get the result <code>'hello'</code>. Let's extend this further to handle the case where <code>foo</code> is possibly <code>undefined</code> using optional chaining.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> Foo {
  bar: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">const</span> foo = {
  bar: <span class="hljs-string">'hello'</span>,
} <span class="hljs-keyword">as</span> Foo | <span class="hljs-literal">undefined</span>

pipe(foo, <span class="hljs-function">(<span class="hljs-params">f</span>) =&gt;</span> f?.bar) <span class="hljs-comment">// hello</span>
</code></pre>
<p>As expected, we get <code>'hello'</code> again. But we can do better here. We have a named variable <code>f</code> in our anonymous function. In general, we want to avoid this. This is because it puts us at risk of shadowing an outer variable. Another reason is the difficulty of naming the variable. It is named <code>f</code>, but you could name it <code>nullableFoo</code>. Bottom line is, there is no good name for this variable.</p>
<p>Let's use object destructuring to solve this problem.</p>
<pre><code class="lang-ts">pipe(foo, <span class="hljs-function">(<span class="hljs-params">{ bar }</span>) =&gt;</span> bar) <span class="hljs-comment">// Property 'bar' does not exist on type 'Foo | undefined'.ts (2339)</span>
</code></pre>
<blockquote>
<p>Property 'bar' does not exist on type 'Foo | undefined'.ts (2339)</p>
</blockquote>
<p>Oops. The compiler can't destructure an object that is possibly <code>undefined</code>.</p>
<p>Enter the Option type.</p>
<pre><code class="lang-ts">pipe(
  foo,
  O.fromNullable,
  O.map(<span class="hljs-function">(<span class="hljs-params">{ bar }</span>) =&gt;</span> bar),
) <span class="hljs-comment">// { _tag: 'Some', value: 'hello' }</span>
pipe(
  <span class="hljs-literal">undefined</span>,
  O.fromNullable,
  O.map(<span class="hljs-function">(<span class="hljs-params">{ bar }</span>) =&gt;</span> bar),
) <span class="hljs-comment">// { _tag: 'None' }</span>
</code></pre>
<p>After replacing the anonymous function with a <code>map</code> function from the Option module, the compiler no longer complains. Why is this?</p>
<p>Let's start by looking at the output of both pipes. In the first pipe, we have <code>{ _tag: 'Some', value: 'hello' }</code>. This is in comparison to the original output, <code>'hello'</code>. Likewise, the second pipe does not output <code>undefined</code> but instead, outputs <code>{ _tag: 'None' }</code>.</p>
<p>Intuitively, this must imply our map function is not operating over the raw values: <code>'hello'</code> or <code>undefined</code> but rather, over a container object.</p>
<p>The second operation in our <code>pipe</code> function, <code>O.fromNullable</code> creates this container object. It <em>lifts</em> the nullable value into the container by adding a <code>_tag</code> property to discriminate whether the Option is <code>Some</code> or <code>None</code>. The value is dropped if the <code>_tag</code> is <code>None</code>.</p>
<p>Going back to our <code>map</code> function. How does <code>O.map</code> work over the Option container? It works by performing a comparison over the <code>_tag</code> property. If the <code>_tag</code> is <code>Some</code>, it transforms the value using the function passed into <code>map</code>. In this case, we transformed it using <code>({ bar }) =&gt; bar</code>. However, if the <code>_tag</code> is <code>None</code>, no operation is performed. The container remains in the <code>None</code> state.</p>
<h2 id="heading-flatten">Flatten</h2>
<p>How would we handle a situation where the object has sequentially nested nullable properties? Let's extend the example we had above.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> Fizz {
  buzz: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">interface</span> Foo {
  bar?: Fizz
}

<span class="hljs-keyword">const</span> foo = { bar: <span class="hljs-literal">undefined</span> } <span class="hljs-keyword">as</span> Foo | <span class="hljs-literal">undefined</span>

pipe(foo, <span class="hljs-function">(<span class="hljs-params">f</span>) =&gt;</span> f?.bar?.buzz) <span class="hljs-comment">// undefined</span>
</code></pre>
<p>To make this work with optional chaining, we only needed to add another question mark. How would this look like using the Option type?</p>
<pre><code class="lang-ts">pipe(
  foo,
  O.fromNullable,
  O.map(<span class="hljs-function">(<span class="hljs-params">{ bar: { buzz } }</span>) =&gt;</span> buzz),
)
</code></pre>
<blockquote>
<p>Property 'buzz' does not exist on type 'Fizz | undefined'.ts (2339)</p>
</blockquote>
<p>Sadly, we run in the same problem we had before. That is, object destructuring cannot be used over a type that is possibly <code>undefined</code>.</p>
<p>What we can do is <em>lift</em> both <code>foo</code> and <code>bar</code> into Option types using <code>O.fromNullable</code> twice.</p>
<pre><code class="lang-ts">pipe(
  foo,
  O.fromNullable,
  O.map(<span class="hljs-function">(<span class="hljs-params">{ bar }</span>) =&gt;</span>
    pipe(
      bar,
      O.fromNullable,
      O.map(<span class="hljs-function">(<span class="hljs-params">{ buzz }</span>) =&gt;</span> buzz),
    ),
  ),
) <span class="hljs-comment">// { _tag: 'Some', value: { _tag: 'None' } }</span>
</code></pre>
<p>But now we've created two new problems. First, it's horribly verbose. Second, we have a nested Option. Look at the <code>_tag</code> of both the outer and inner Option. The first one is <code>Some</code>, which we expect because <code>foo.bar</code> is defined. The second one is <code>None</code> because <code>foo.bar.buzz</code> is <code>undefined</code>. If you only cared about the result of the final Option, you would need to traverse the Option's nested list of tags every time.</p>
<p>Given that we only care about the final Option, could we <em>flatten</em> this nested Option into a single Option?</p>
<p>Introducing the <code>O.flatten</code> operator.</p>
<pre><code class="lang-ts">pipe(
  foo,
  O.fromNullable,
  O.map(<span class="hljs-function">(<span class="hljs-params">{ bar }</span>) =&gt;</span>
    pipe(
      bar,
      O.fromNullable,
      O.map(<span class="hljs-function">(<span class="hljs-params">{ buzz }</span>) =&gt;</span> buzz),
    ),
  ),
  O.flatten,
) <span class="hljs-comment">// { _tag: 'None' }</span>
</code></pre>
<p>We now have a single Option, <code>{ _tag: 'None' }</code> that represents the last Option in the pipeline. If we wanted to check whether this Option was <code>Some</code> or <code>None</code>, we can pipe the result into <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Option.ts.html#issome" o-href="https://gcanti.github.io/fp-ts/modules/Option.ts.html#issome">O.some</a> or <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Option.ts.html#isnone" o-href="https://gcanti.github.io/fp-ts/modules/Option.ts.html#isnone">O.none</a>.</p>
<p>However, we still have the problem of verbosity. It would be beneficial if we could both map and flatten the nested option with a single operator. Intuitively, this is often called a <em>flatmap</em> operator.</p>
<h2 id="heading-chain-flatmap">Chain (Flatmap)</h2>
<p>In fp-ts, the flatmap operator is called <code>chain</code>. We can refactor the above code into the following.</p>
<pre><code class="lang-ts">pipe(
  foo,
  O.fromNullable,
  O.map(<span class="hljs-function">(<span class="hljs-params">{ bar }</span>) =&gt;</span> bar),
  O.chain(
    flow(
      O.fromNullable,
      O.map(<span class="hljs-function">(<span class="hljs-params">{ buzz }</span>) =&gt;</span> buzz),
    ),
  ),
) <span class="hljs-comment">// { _tag: 'None' }</span>
</code></pre>
<p>In short, we achieve the same result with less.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In most cases, you won't need to use Option; optional chaining is less verbose. But the Option type is more than just checking for <code>null</code>. Options can be used to represent failing operations. And just like how you can lift <code>undefined</code> into an Option, you can also lift an Option into another fp-ts container, like <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Either.ts.html#fromoption" o-href="https://gcanti.github.io/fp-ts/modules/Either.ts.html#fromoption">Either</a>.</p>
<p>Checkout the official <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/Option.ts.html" o-href="https://gcanti.github.io/fp-ts/modules/Option.ts.html">Option documentation</a> for more info.</p>
]]></content:encoded></item><item><title><![CDATA[Practical Guide to Fp-ts P1: Pipe and Flow]]></title><description><![CDATA[⚠️ Disclaimer Warning
  
    fp-ts is now dead. Please use effect-ts instead.
  
  
    Update 2024: effect-ts is the recommended library for functional programming in TypeScript.
  


Introduction
This post is an introduction to fp-ts, a functional ...]]></description><link>https://rlee.dev/practical-guide-to-fp-ts-part-1</link><guid isPermaLink="true">https://rlee.dev/practical-guide-to-fp-ts-part-1</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[Functional Programming]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Sat, 13 Jun 2020 23:35:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1618011322566/cVAotP3y-.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div>
  <h3>⚠️ Disclaimer Warning</h3>
  <p>
    <strong>fp-ts</strong> is now dead. Please use <a href="/s/website/effect/G.https/" o-href="https://effect.website/" target="_blank"><strong>effect-ts</strong></a> instead.
  </p>
  <p>
    <em>Update 2024: effect-ts is the recommended library for functional programming in TypeScript.</em>
  </p>
</div>

<h2 id="heading-introduction">Introduction</h2>
<p>This post is an introduction to <a target="_blank" href="/s/com/github/G.https/gcanti/fp-ts" o-href="https://github.com/gcanti/fp-ts">fp-ts</a>, a functional programming library for Typescript. Why should you be learning fp-ts? The first reason is better type safety. Fp‑ts allows you to make assertions about your data structures without writing <a target="_blank" href="/s/org/typescriptlang/www/G.https/docs/handbook/advanced-types.html#user-defined-type-guards" o-href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards">user-defined type guards</a> or using the <code>as</code> operator. The second reason is expressiveness and readability. Fp-ts gives you the tools necessary to elegantly model a sequence of operations that can fail. All in all, you should add fp-ts to your repertoire of tools because it will help you write better Typescript programs.</p>
<p>Contrary to popular opinion, you don’t need to understand complex mathematics to learn functional programming. In truth, you just need to get a feel for how each operator works. Once you get a handle on the basic operators, you can go back and review the mathematics. With this in mind, this post and the ones that follow, I will introduce functional programming from a practical perspective, avoiding mathematical jargon unless necessary.</p>
<h2 id="heading-the-pipe-operator">The Pipe Operator</h2>
<p>The basic building block of fp-ts is the <a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/function.ts.html#pipe" o-href="https://gcanti.github.io/fp-ts/modules/function.ts.html#pipe">Pipe</a> operator. Intuitively, you can use the operator to chain a sequence of functions from left-to-right. The type definition of <code>pipe</code> takes an arbitrary number of arguments. The first argument can be any arbitrary value and subsequent arguments must be functions of <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Arity" o-href="https://en.wikipedia.org/wiki/Arity">arity</a> one. The return type of a preceding function in the pipeline must match the input type of the subsequent function.</p>
<p>Let's look at how to pipe simple addition and multiplication functions.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { pipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/function'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add1</span>(<span class="hljs-params">num: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">number</span> </span>{
  <span class="hljs-keyword">return</span> num + <span class="hljs-number">1</span>
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">multiply2</span>(<span class="hljs-params">num: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">number</span> </span>{
  <span class="hljs-keyword">return</span> num * <span class="hljs-number">2</span>
}

pipe(<span class="hljs-number">1</span>, add1, multiply2) <span class="hljs-comment">// 4</span>
</code></pre>
<p>The result of this operation is <code>4</code>. How did we arrive at this result? Let’s look at the steps.</p>
<ol>
<li>We start with the value of <code>1</code>.</li>
<li><code>1</code> is piped into the first argument of <code>add1</code> and <code>add1</code> is evaluated to <code>2</code> by adding <code>1</code>.</li>
<li>The return value of <code>add1</code>, <code>2</code> is piped into the first argument <code>multiply2</code> and is evaluated to <code>4</code> by multiplying by <code>2</code>.</li>
</ol>
<p>Currently our pipeline inputs a number and outputs a new number. Is it possible to transform the input type to another type, like a <code>string</code>? The answer is yes. Let’s add a <code>toString</code> function at the end of the pipeline.</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toString</span>(<span class="hljs-params">num: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">string</span> </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${num}</span>`</span>
}

pipe(<span class="hljs-number">1</span>, add1, multiply2, toString) <span class="hljs-comment">// '4'</span>
</code></pre>
<p>Now our pipeline evaluates to <code>’4’</code>. What happens if we were to put <code>toString</code> between <code>add1</code> and <code>multiply2</code>? We get a compile error because the output type of <code>toString</code>, <code>string</code> does not match the input type of <code>multiply2</code>, <code>number</code>.</p>
<pre><code class="lang-ts">pipe(<span class="hljs-number">1</span>, add1, toString, multiply2)
</code></pre>
<blockquote>
<p>Argument of type '(num: number) =&gt; string' is not assignable to parameter of type '(b: number) =&gt; number'.
Type 'string' is not assignable to type 'number'.ts (2345)</p>
</blockquote>
<p>In short, you can use the <code>pipe</code> operator to transform any value using a sequence of functions. The flow of control can be modelled as follows. [^1]</p>
<pre><code class="lang-java">A -&gt; (A-&gt;B) -&gt; (B-&gt;C) -&gt; (C-&gt;D)
</code></pre>
<h2 id="heading-the-flow-operator">The Flow Operator</h2>
<p>The <code>flow</code> operator is almost analogous to the <code>pipe</code> operator. The difference being the first argument must be a function, rather than any arbitrary value, say a number. The first function is also allowed to have an arity of more than one.</p>
<p>For example, we could wrap our three functions inside of the <code>flow</code> operator.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { flow } <span class="hljs-keyword">from</span> <span class="hljs-string">'fp-ts/lib/function'</span>

pipe(<span class="hljs-number">1</span>, flow(add1, multiply2, toString))
flow(add1, multiply2, toString)(<span class="hljs-number">1</span>) <span class="hljs-comment">// this is equivalent</span>
</code></pre>
<p>In comparison, to the <code>pipe</code> operator, this is what the "flow" of control looks like for the <code>flow</code> operator. [^2]</p>
<pre><code class="lang-java">(A-&gt;B) -&gt; (B-&gt;C) -&gt; (C-&gt;D) -&gt; (D-&gt;E)
</code></pre>
<p>What is a good use case for the <code>flow</code> operator? When should you use it over the <code>pipe</code> operator? A general rule of thumb is when you want to avoid using an anonymous function. In Typescript, a good example of an anonymous function are callbacks.</p>
<p>Lets declare a function, <code>concat</code> with arity of <code>2</code>. The first argument will be a number. The second argument is a callback that takes a number as its first argument and transforms it into a string. The function returns the first value and the transformed second value as a two dimensional <a target="_blank" href="/s/org/wikipedia/en/G.https/wiki/Tuple" o-href="https://en.wikipedia.org/wiki/Tuple">tuple</a>.</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">concat</span>(<span class="hljs-params">
  a: <span class="hljs-built_in">number</span>,
  transformer: (a: <span class="hljs-built_in">number</span>) =&gt; <span class="hljs-built_in">string</span>,
</span>): [<span class="hljs-title">number</span>, <span class="hljs-title">string</span>] </span>{
  <span class="hljs-keyword">return</span> [a, transformer(a)]
}
</code></pre>
<p>Using our previous repertoire of functions, we can compose a callback for this function. Here is an example using the <code>pipe</code> operator.</p>
<pre><code class="lang-ts">concat(<span class="hljs-number">1</span>, <span class="hljs-function">(<span class="hljs-params">n</span>) =&gt;</span> pipe(n, add1, multiply2, toString)) <span class="hljs-comment">// [1, '4']</span>
</code></pre>
<p>What’s the problem with this? The problem is we have to declare <code>n</code> as part of an anonymous function to use it with the <code>pipe</code> operator. You should avoid this because it puts you at risk of shadowing a variable in the outer scope. It is also more verbose.</p>
<p>The solution is to use the <code>flow</code> operator and remove the anonymous function. This works because the return value of <code>flow</code> is a function itself. The signature of this function is <code>number -&gt; string</code> which is exactly the same as the callback signature.</p>
<pre><code class="lang-ts">concat(<span class="hljs-number">1</span>, flow(add1, multiply2, toString)) <span class="hljs-comment">// [1, '4']</span>
</code></pre>
<hr />
<h2 id="heading-appendix">Appendix</h2>
<ul>
<li><a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/function.ts.html#pipe" o-href="https://gcanti.github.io/fp-ts/modules/function.ts.html#pipe">Pipe Typescript Definition</a></li>
<li><a target="_blank" href="/s/io/github/gcanti/G.https/fp-ts/modules/function.ts.html#flow" o-href="https://gcanti.github.io/fp-ts/modules/function.ts.html#flow">Flow Typescript Definition</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[A Short Guide To VSCode Hotkey Mastery]]></title><description><![CDATA[Introduction
The first step to becoming a good developer is to understand your text editor. Like many, I use VSCode and over the years I have discovered features that I failed to realize even existed. These features have improved my productivity and ...]]></description><link>https://rlee.dev/a-short-guide-to-vscode-hotkey-mastery</link><guid isPermaLink="true">https://rlee.dev/a-short-guide-to-vscode-hotkey-mastery</guid><category><![CDATA[Visual Studio Code]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Tue, 26 May 2020 20:00:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1617891433175/wBIx2qHVE.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>The first step to becoming a good developer is to understand your text editor. Like many, I use VSCode and over the years I have discovered features that I failed to realize even existed. These features have improved my productivity and my confidence as a developer. As such, I am obliged to share, in this post, the hotkeys that have improved my editing experience the most.</p>
<p>The first two categories of hotkeys I will introduce are <a class="post-section-overview" href="#command-palette">Command</a> and <a class="post-section-overview" href="#navigation">Navigation</a>. The command palette is an important tool because it allows you to explore the full range of possibilities that exist in the editor. Likewise, navigation is important because it helps you dig into a codebase and follow links between dependencies easily. However, the deeper you go, the more important it is to know how to navigate back to where you came from. The <a class="post-section-overview" href="#editing">Editing</a> category is all about maximizing keyboard usage efficiency and avoiding unnecessary usage of the mouse. Getting your cursor in the right position or selecting blocks of text are examples of keyboard usage efficiency.</p>
<h2 id="command-palette">Command Palette</h2>
<p>Keyboard Shortcut: <code>Ctrl+Shift+P</code></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/f42ad8e15a4b44b1bd9c9a2d52696955" o-href="https://www.loom.com/share/f42ad8e15a4b44b1bd9c9a2d52696955">https://www.loom.com/share/f42ad8e15a4b44b1bd9c9a2d52696955</a></div>
<p>The command palette is like Google in your browser; it lets you discover what is possible in your editor. When you open the command palette, you will notice the search bar is prefixed with <code>&gt;</code>. This is how VSCode knows you are inputting a command. If you remove the <code>&gt;</code>, it becomes a search engine for any files in your current working directory.</p>
<h2 id="reload-window">Reload Window</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/24f75921c20a4c8d86061583fdf080ae" o-href="https://www.loom.com/share/24f75921c20a4c8d86061583fdf080ae">https://www.loom.com/share/24f75921c20a4c8d86061583fdf080ae</a></div>
<p>The first command I will introduce is <strong>Reload Window</strong>. This handy when your terminal freezes or when an extension that requires a reload is updated; Its less work than manually closing VSCode and reopening it. Another reason is the interoperability between Linux machines and NVIDIA graphics cards. From my experience, whenever my computer wakes up from sleep, the integrated terminal becomes corrupted with visual artifacts. There are two ways of fixing this: kill all your terminals or reload the window; I choose the latter option.</p>
<h3 id="format-document">Format Document</h3>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/bc43b1de4ec1418a901cb8d67cf3ecbe" o-href="https://www.loom.com/share/bc43b1de4ec1418a901cb8d67cf3ecbe">https://www.loom.com/share/bc43b1de4ec1418a901cb8d67cf3ecbe</a></div>
<p>The second command is <strong>Format Document</strong>. I rarely use this command when I'm programming because I have <strong>Format on Save</strong> turned on. When trying to debug, it comes in handy. The most common use-case is when I want to read the minified JSON printed in terminal. To do this, I create a new file, paste the minified JSON, set the language to JSON, and run the <strong>Format Document</strong>.</p>
<h3 id="save-without-formatting">Save Without Formatting</h3>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/eb2c6ae40c0a4a6aa321e636f88a5832" o-href="https://www.loom.com/share/eb2c6ae40c0a4a6aa321e636f88a5832">https://www.loom.com/share/eb2c6ae40c0a4a6aa321e636f88a5832</a></div>
<p>Similarly, the third command is <strong>Save without Formatting</strong>. This command is useful when you are working on a team with a repository that is riddled with linter and formatting errors. Assuming you have <strong>Format on Save</strong> turned on, saving any file in this repository would create a large Git diff; its courtesy for small changes to have small diffs. Leave the formatting for a separate, isolated PR.</p>
<h2 id="navigation">Navigation</h2>
<h3 id="go-to-definition">Go to Definition</h3>
<p>Keyboard Shortcut: <code>F12</code></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/a74a6aeff31d4e7f87fb64b9b3ca9c7c" o-href="https://www.loom.com/share/a74a6aeff31d4e7f87fb64b9b3ca9c7c">https://www.loom.com/share/a74a6aeff31d4e7f87fb64b9b3ca9c7c</a></div>
<p><strong>Go to Definition</strong> is your bread and butter for navigation. Use this when you are integrating with third party libraries. Being able to inspect the function definition and type declaration is essential because it gives you a better understanding about how the library was designed to be used. My biggest qualm with <strong>Go To Defintion</strong> is getting stuck in a ditch because I'm using the command recursively. Its easy to get lost because its so hard to retrace through all the new files that were opened. The key discovery to overcome this is the <strong>Go Back</strong> operation.</p>
<h3 id="go-backforward">Go Back/Forward</h3>
<p>Keyboard Shortcut: <code>CTRL+ALT+➖</code>/<code>CTRL+ALT+➕</code></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/b20289391eed4248abfedd1b3f2b143e" o-href="https://www.loom.com/share/b20289391eed4248abfedd1b3f2b143e">https://www.loom.com/share/b20289391eed4248abfedd1b3f2b143e</a></div>
<p><strong>Go Back</strong> is self explanatory, it lets you go back after a navigation command. What I despise about <strong>Go Back</strong> is when you have the same file opened in two split panes, the <strong>Go Back</strong> operation refocuses the window on the wrong pane. What I expect is for it to go back to the pane I called <strong>Go To Definition</strong> in. <strong>Go Forward</strong> is the same story but in reverse.</p>
<h3 id="control-arrow-keys-home-end">Control Arrow Keys / Home / End</h3>
<p>Keyboard Shortcuts: 
<code>CTRL+ALT+LEFT_ARROW</code>,<code>CTRL+ALT+RIGHT_ARROW</code>, <code>HOME</code>, <code>END</code></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/f623849027d24b86b84465d6cbcf46b3" o-href="https://www.loom.com/share/f623849027d24b86b84465d6cbcf46b3">https://www.loom.com/share/f623849027d24b86b84465d6cbcf46b3</a></div>
<p>I'm sure you've seen somebody who just holds down the arrow key on their keyboard and waits for the cursor to move to the right spot. That is extremely inefficient and wasteful. Jump between words and delimiters using <strong>Control Arrow Keys</strong>. If the distance is too far, use the <strong>Home</strong> and <strong>End</strong> buttons to your advantage.</p>
<h2 id="editing">Editing</h2>
<h3 id="cut">Cut</h3>
<p>Keyboard Shortcut: <code>Ctrl+X</code></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/bdfde710884e49cfa2e421058670859c" o-href="https://www.loom.com/share/bdfde710884e49cfa2e421058670859c">https://www.loom.com/share/bdfde710884e49cfa2e421058670859c</a></div>
<p>I use the cut hotkey to delete lines more often than to actually cut and paste text. This is because you can cut a line if you have nothing selected under your cursor. I find this to be more effective than the delete line hotkey because there are less bindings I need to remember, <code>CTRL+X</code> is simple to build into muscle memory, and you always have the option of repasting the line.</p>
<h3 id="column-select">Column Select</h3>
<p>Keyboard Shortcut: <code>ALT+DOWN_ARROW</code>/<code>ALT+UP_ARROW</code></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/18bf692d01c3490e90ed27217a75e477" o-href="https://www.loom.com/share/18bf692d01c3490e90ed27217a75e477">https://www.loom.com/share/18bf692d01c3490e90ed27217a75e477</a></div>
<p>Column select is necessary when you are trying to select lines that have the same column delimiter or prefix. This video shows how I column selected in front of <code>import</code>, used <strong>Control Arrow Keys</strong> to select it all and replaced it with a require statement.</p>
<h3 id="add-current-word-to-selection">Add Current Word To Selection</h3>
<p>Keyboard Shortcut: <code>Ctrl+W</code></p>
<p><strong>Add Current Word To Selection</strong> is useful when you want to select the word thats under your cursor quickly. Often times I use this to delete the word or use it to pre-fill a <strong>Find</strong> (<code>CTRL+F</code>) command.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/0a56f7a4e66b4320a80cbe08951515a1" o-href="https://www.loom.com/share/0a56f7a4e66b4320a80cbe08951515a1">https://www.loom.com/share/0a56f7a4e66b4320a80cbe08951515a1</a></div>
<h2 id="conclusion">Conclusion</h2>
<p>These are all the hotkeys you need to be an effective and quick developer. Checkout the video below for a combination of most of them. 😉</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="/s/com/loom/www/G.https/share/92354c6c3a7a499893a149bd62e13899" o-href="https://www.loom.com/share/92354c6c3a7a499893a149bd62e13899">https://www.loom.com/share/92354c6c3a7a499893a149bd62e13899</a></div>
]]></content:encoded></item><item><title><![CDATA[Stop Misusing Typescript String Enums]]></title><description><![CDATA[Introduction
String enums were a feature that was introduced in version 2.4.
Since then, we have preferred using string enums over numeric enums because it better
demonstrate the developer's intent. However, there a severe drawbacks to the usage of
s...]]></description><link>https://rlee.dev/stop-misusing-typescript-string-enums</link><guid isPermaLink="true">https://rlee.dev/stop-misusing-typescript-string-enums</guid><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Ryan Lee]]></dc:creator><pubDate>Wed, 20 May 2020 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1617912448347/n4qs6NSKl.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>String enums were a feature that was introduced in version <a target="_blank" href="/s/org/typescriptlang/www/G.https/docs/handbook/release-notes/typescript-2-4.html" o-href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html">2.4</a>.
Since then, we have preferred using string enums over numeric enums because it better
demonstrate the developer's intent. However, there a severe drawbacks to the usage of
string enums; strong-typing being one of them. This has been detrimental to the Typescript
developer experience because tools outside of an individual developer control such as
software development kits and code generation tools are filled with string enums.</p>
<p>In this post I will teach you about the problems enums were meant to solve and its
drawbacks. I will demonstrate how constant objects and discriminated
unions work and how they can be used as an alternative to string enums.</p>
<h2 id="heading-the-problem-enums-were-meant-to-solve">The Problem Enums Were Meant to Solve</h2>
<p>Imagine you had two sets of values. One for credit card type: <code>VISA</code>, <code>Mastercard</code>, <code>AMEX</code>
and one for shipping type: <code>Standard</code>, <code>Express</code>, <code>Next-Day</code>. Logically, we can group
these sets in two separate enums.</p>
<pre><code class="lang-ts"><span class="hljs-built_in">enum</span> CreditCardType {
  VISA,
  MASTERCARD,
  AMEX
}

<span class="hljs-built_in">enum</span> ShippingType {
  STANDARD,
  EXPRESS,
  NEXTDAY
}
</code></pre>
<p>Each enum member has an underlying sequential value. In this case, it ranges from 0-2.
Hence, what would happen if we were to compare VISA to STANDARD? Both have an underlying value of 0.
It must follow that they are equal. Or so we may think.</p>
<p>In a statically typed language, the compiler would prevent this comparison. It would
be illogical to compare a credit card type with a shipping type.
Hence, every enum must have its own unique type. From an object-oriented perspective,
you can consider every enum to be a class.</p>
<h2 id="heading-string-enums">String Enums</h2>
<p>String enums are a considerable upgrade from numerical enums. This is because it
gives the underlying data type a comprehensible value. It also makes debugging easier
because it is identifiable in a print statement.</p>
<p>Here is what the two enums above would look like as string enums.</p>
<pre><code class="lang-ts"><span class="hljs-built_in">enum</span> CreditCardType {
  VISA = <span class="hljs-string">'VISA'</span>,
  MASTERCARD = <span class="hljs-string">'MASTERCARD'</span>,
  AMEX = <span class="hljs-string">'AMEX'</span>
}


<span class="hljs-built_in">enum</span> ShippingType {
  STANDARD = <span class="hljs-string">'STANDARD'</span>,
  EXPRESS = <span class="hljs-string">'EXPRESS'</span>,
  NEXTDAY = <span class="hljs-string">'NEXTDAY'</span>
}
</code></pre>
<p>If we were to compare VISA to STANDARD again, they would not be equal because
the underlying values are different. However, a statically typed compiler will
still enforce the enum invariant. The comparison remains impossible. The illogical
nature of comparing a credit card type to a shipping type has not changed.</p>
<h2 id="heading-drawbacks-of-string-enums">Drawbacks of String Enums</h2>
<p>If strong typing was a benefit for numeric enums, it is huge drawback for
string enums.</p>
<p>Imagine you are using an SDK provided by a third party for their shipping service.
They provide an interface using the <code>ShippingType</code> enum above. For business reasons,
you only want your customers to specify standard or express shipping. You decide
to create you own enum for your web application controller. Because your enum is
narrower than the SDK's enum, you expect there to be no problem passing it
straight the SDK.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">namespace</span> FastShippersCo {
  <span class="hljs-keyword">export</span> <span class="hljs-built_in">enum</span> ShippingType {
    STANDARD = <span class="hljs-string">'STANDARD'</span>,
    EXPRESS = <span class="hljs-string">'EXPRESS'</span>,
    NEXTDAY = <span class="hljs-string">'NEXTDAY'</span>,
  }

  <span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> ShippingService {
    ship(<span class="hljs-keyword">type</span>: ShippingType): <span class="hljs-built_in">void</span>
  }
}

<span class="hljs-keyword">namespace</span> TShirtsOnline {
  <span class="hljs-built_in">enum</span> OrderShippingType {
    STANDARD = <span class="hljs-string">'STANDARD'</span>,
    EXPRESS = <span class="hljs-string">'EXPRESS'</span>,
  }

  <span class="hljs-keyword">class</span> ShippingDetailsDTO {
    <span class="hljs-keyword">type</span>!: OrderShippingType
  }

  <span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> shippingService: FastShippersCo.ShippingService
  <span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> shippingDetails: ShippingDetailsDTO

  <span class="hljs-comment">// Argument of type 'OrderShippingType' is not assignable to parameter of type 'ShippingType'. ts(2345)</span>
  <span class="hljs-comment">// highlight-next-line</span>
  shippingService.ship(shippingDetails.type)
}
</code></pre>
<blockquote>
<p>Argument of type <code>OrderShippingType</code> is not assignable to parameter of type <code>ShippingType</code>.</p>
</blockquote>
<p>The purpose of strong typing was to prevent accidents when comparing numeric enums.
There are no accidents for string enums. The developer's intent is always clear.
The compiler error here is a real pain to deal with because it causes unnecessary
obstruction. Compounded with the fact that there are no easy ways around it.</p>
<p>Casting is not a solution.</p>
<pre><code class="lang-ts">shippingService.ship(shippingDetails.type <span class="hljs-keyword">as</span> FastShippersCo.ShippingType)
</code></pre>
<blockquote>
<p>Conversion of type <code>OrderShippingType</code> to type <code>ShippingType</code> may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to <code>unknown</code> first. ts(2352)</p>
</blockquote>
<p>Mapping works, but it is highly verbose.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">switch</span> (shippingDetails.type) {
  <span class="hljs-keyword">case</span> OrderShippingType.STANDARD:
    shippingService.ship(FastShippersCo.ShippingType.STANDARD)
  <span class="hljs-keyword">case</span> OrderShippingType.EXPRESS:
    shippingService.ship(FastShippersCo.ShippingType.EXPRESS)
}
</code></pre>
<h2 id="heading-discriminated-unions">Discriminated Unions</h2>
<p>A great alternative to string enums are discriminated unions. The primary difference
between a string enum and a discriminated union is the lack of strong typing. This
is exactly what we want.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> ShippingType = <span class="hljs-string">'STANDARD'</span> | <span class="hljs-string">'EXPRESS'</span> | <span class="hljs-string">'NEXT_DAY'</span>
</code></pre>
<p>There is a problem with this approach. We cannot directly reference the type without
using a string literal. We want to preserve the ability to do this:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> shippingType = FastShippersCo.ShippingType.STANDARD
</code></pre>
<p>What we could also do is also export an object containing the enums values and extract
the type based on the enum's values. Remember we can export a type and an object
with the same name because types are erased after transpilation.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ShippingType = {
  STANDARD: <span class="hljs-string">'STANDARD'</span> <span class="hljs-keyword">as</span> <span class="hljs-string">'STANDARD'</span>,
  EXPRESS: <span class="hljs-string">'EXPRESS'</span> <span class="hljs-keyword">as</span> <span class="hljs-string">'EXPRESS'</span>,
  NEXTDAY: <span class="hljs-string">'NEXTDAY'</span> <span class="hljs-keyword">as</span> <span class="hljs-string">'NEXTDAY'</span>,
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> ShippingType =
  | <span class="hljs-keyword">typeof</span> ShippingType.STANDARD
  | <span class="hljs-keyword">typeof</span> ShippingType.EXPRESS
  | <span class="hljs-keyword">typeof</span> ShippingType.NEXTDAY
</code></pre>
<p>We can make a minor adjustment using <a target="_blank" href="/s/org/typescriptlang/www/G.https/docs/handbook/release-notes/typescript-3-4.html#const-assertions" o-href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions">as const</a> to prevent code duplication.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ShippingType = {
  STANDARD: <span class="hljs-string">'STANDARD'</span>,
  EXPRESS: <span class="hljs-string">'EXPRESS'</span>,
  NEXTDAY: <span class="hljs-string">'NEXTDAY'</span>,
} <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> ShippingType =
  | <span class="hljs-keyword">typeof</span> ShippingType.STANDARD
  | <span class="hljs-keyword">typeof</span> ShippingType.EXPRESS
  | <span class="hljs-keyword">typeof</span> ShippingType.NEXTDAY
</code></pre>
<p>Finally, we can leverage <code>keyof</code> and <code>typeof</code> to turn our type into a one liner.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ShippingType = {
  STANDARD: <span class="hljs-string">'STANDARD'</span>,
  EXPRESS: <span class="hljs-string">'EXPRESS'</span>,
  NEXTDAY: <span class="hljs-string">'NEXTDAY'</span>,
} <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> ShippingType = <span class="hljs-keyword">typeof</span> ShippingType[keyof <span class="hljs-keyword">typeof</span> ShippingType]
</code></pre>
<p>To understand how this works, first evaluate <code>keyof typeof ShippingType</code>. This is
an expansion of all the keys in ShippingType.</p>
<pre><code class="lang-ts"><span class="hljs-string">'STANDARD'</span> | <span class="hljs-string">'EXPRESS'</span> | <span class="hljs-string">'NEXTDAY'</span>
</code></pre>
<p>For each one of these values, it indexes the ShippingType object to get the following.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">typeof</span> ShippingType[<span class="hljs-string">'STANDARD'</span>] | <span class="hljs-keyword">typeof</span> ShippingType[<span class="hljs-string">'EXPRESS'</span>] | <span class="hljs-keyword">typeof</span> ShippingType[<span class="hljs-string">'NEXTDAY'</span>]
</code></pre>
<p>This is what the final type looks like when we hover our mouse over it.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> FastShippersCo.ShippingType = <span class="hljs-string">'STANDARD'</span> | <span class="hljs-string">'EXPRESS'</span> | <span class="hljs-string">'NEXTDAY'</span>
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Never use string enums. Always favour discriminated unions. Code generation
tools, especially those written in other programming languages must be aware of this fact.
Adoption of these tools will increase as more developers adopt <a target="_blank" href="/s/org/openapis/www/G.https/" o-href="https://www.openapis.org/">OpenAPI</a>
standards. SDK designers and library designers must also take notice.</p>
]]></content:encoded></item></channel></rss>