<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gio</title>
    <description>The latest articles on DEV Community by Gio (@_gdelgado).</description>
    <link>https://dev.to/_gdelgado</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F65651%2F30f5908d-3b9f-4c03-83f6-6605c3c7d667.jpg</url>
      <title>DEV Community: Gio</title>
      <link>https://dev.to/_gdelgado</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_gdelgado"/>
    <language>en</language>
    <item>
      <title>Pitfalls When Adding Turborepo To Your Project</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Tue, 15 Feb 2022 14:23:09 +0000</pubDate>
      <link>https://dev.to/_gdelgado/pitfalls-when-adding-turborepo-to-your-project-4cel</link>
      <guid>https://dev.to/_gdelgado/pitfalls-when-adding-turborepo-to-your-project-4cel</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally posted at &lt;a href="https://engineering.caribouwealth.com" rel="noopener noreferrer"&gt;https://engineering.caribouwealth.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We at Caribou have recently adopted a new TypeScript monorepo stack for our app frontends using &lt;a href="https://turborepo.org/" rel="noopener noreferrer"&gt;turborepo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues faced with our original monorepo setup
&lt;/h2&gt;

&lt;p&gt;As our number of apps and codebases grew, we decided that we wanted to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save time and money on ever increasing build times

&lt;ul&gt;
&lt;li&gt;Build times were increasing dramatically as we went from 2 apps in our monorepo to 4. The original monorepo setup would naively deploy all apps inside the project on every push to GitHub. Once we got to 4 projects, the build times got really out of hand.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Enable the granular tracking of individual application deployments for our metrics monitoring

&lt;ul&gt;
&lt;li&gt;We strive to do 5 releases per week on average (across all of our projects), and we need to track whether we're hitting these targets or not.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Add CircleCI as a layer between GitHub and Netlify to manage our CI pipeline

&lt;ul&gt;
&lt;li&gt;Our other repos were already on CircleCI, so this allowed us to unify our CI/CD process.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As we’ve faced multiple roadblocks undergoing this transition, we decided to record them for the benefit of developers at Caribou or anyone else undertaking similar endeavours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting point and stack choice
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fengineering.caribouwealth.com%2F_ipx%2Fw_640%2Cq_75%2F%252Fstatic%252Fimages%252Fmonorepo%252F1642780105.png%3Furl%3D%252Fstatic%252Fimages%252Fmonorepo%252F1642780105.png%26w%3D640%26q%3D75" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fengineering.caribouwealth.com%2F_ipx%2Fw_640%2Cq_75%2F%252Fstatic%252Fimages%252Fmonorepo%252F1642780105.png%3Furl%3D%252Fstatic%252Fimages%252Fmonorepo%252F1642780105.png%26w%3D640%26q%3D75" alt="Directory structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We started from a flat file system containing multiple apps that were all located in the project’s root folder. The directory structure itself needed work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Researching &amp;amp; The Design Document Phase
&lt;/h3&gt;

&lt;p&gt;At Caribou, net-new functionality or highly complex additions to our systems must go through a design document process.&lt;/p&gt;

&lt;p&gt;We wrote a design document outlining our requirements and how the new stack would meet them. Our requirements were not complicated. We wanted to rebuild and deploy only those parts of the monorepo that have changed, and add our desired checks on CircleCI. &lt;/p&gt;

&lt;p&gt;We had a first look at monorepo management. We knew &lt;a href="https://lerna.js.org" rel="noopener noreferrer"&gt;Lerna&lt;/a&gt; was a popular choice, but &lt;a href="https://turborepo.org" rel="noopener noreferrer"&gt;Turborepo&lt;/a&gt; had recently been acquired by Vercel and seemed highly promising. It purported to be very fast but simpler than Lerna, and one of our engineers had a positive experience with it.&lt;/p&gt;

&lt;p&gt;After a few days of playing around with Turborepo, we concluded that its simple and intuitive API was sufficient justification to proceed with it as our tool of choice.&lt;/p&gt;

&lt;p&gt;Turborepo works with one of Yarn, npm, or pnpm workspaces. We already used npm as a package manager, so in order to keep things familiar we went with npm workspaces.&lt;/p&gt;

&lt;p&gt;Finally, we already used CircleCI for our backend CI, so we wanted to keep using&lt;br&gt;
CircleCI on the frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the npm workspace
&lt;/h2&gt;

&lt;p&gt;This is &lt;a href="https://turborepo.org/docs/getting-started#ensure-workspaces-are-configured" rel="noopener noreferrer"&gt;easily done inside the root &lt;code&gt;package.json&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run &lt;code&gt;npm install&lt;/code&gt; to create the symlinks inside &lt;code&gt;node_modules&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;One thing to note is to not forget to rerun &lt;code&gt;npm install&lt;/code&gt; at the project root (we initially did...). If you forget, npm won’t create the symlinks to your workspaces/packages inside &lt;code&gt;node_modules&lt;/code&gt;, and you won’t be able to use absolute paths to other modules inside your imports. &lt;/p&gt;

&lt;h3&gt;
  
  
  npm v7 is needed or the IDE/compiler can't resolve modules
&lt;/h3&gt;

&lt;p&gt;Even if you run &lt;code&gt;npm install&lt;/code&gt;, only npm 7 and up support workspaces. &lt;a href="https://github.com/npm/rfcs/discussions/50" rel="noopener noreferrer"&gt;There is no straightforward way to enforce developer npm version&lt;/a&gt; although it is not impossible, so you might want to document the version requirement in your root README. A developer without npm 7+ will end up with unresolved modules in their editor.&lt;/p&gt;

&lt;h3&gt;
  
  
  New commands to install dependencies and run scripts
&lt;/h3&gt;

&lt;p&gt;When using npm packages, you must keep in mind that the commands to install dependencies and run scripts are different.&lt;/p&gt;

&lt;p&gt;Assuming a sub-package named &lt;code&gt;blog&lt;/code&gt;, installing the dependency &lt;code&gt;neverthrow&lt;/code&gt; is done by running this command at the monorepo root:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# DON'T do that anymore&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;neverthrow
&lt;span class="c"&gt;# Do this instead&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--workspace&lt;/span&gt; blog neverthrow
&lt;span class="c"&gt;# or for short&lt;/span&gt;
npm i &lt;span class="nt"&gt;-w&lt;/span&gt; blog neverthrow


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

&lt;/div&gt;

&lt;p&gt;Running the &lt;code&gt;start&lt;/code&gt; script from the &lt;code&gt;blog&lt;/code&gt; subpackage is done with the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Don't do that anymore&lt;/span&gt;
npm run start
&lt;span class="c"&gt;# Do this instead&lt;/span&gt;
npm run &lt;span class="nt"&gt;--workspace&lt;/span&gt; blog start
&lt;span class="c"&gt;# or for short&lt;/span&gt;
npm run &lt;span class="nt"&gt;-w&lt;/span&gt; blog start 


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Separating dependencies
&lt;/h2&gt;

&lt;p&gt;One detail which was not immediately obvious during the transition is that the root &lt;code&gt;package.json&lt;/code&gt; should only contain dev dependencies. (It doesn’t need to be all of them, either.) We initially thought we should keep common dependencies in the root package.json. This caused React errors from having multiple instances of React running. &lt;/p&gt;

&lt;p&gt;Another thing to note is you should never see a &lt;code&gt;package-lock.json&lt;/code&gt; inside a sub-package’s folder. This means the &lt;code&gt;npm install&lt;/code&gt; command was run inside it, which is incorrect! Delete the resulting &lt;code&gt;package-lock.json&lt;/code&gt; as well as the &lt;code&gt;node_modules&lt;/code&gt; it newly installed. When using npm workspaces, all dependencies live in the root &lt;code&gt;node_modules&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Import resolution after transitioning
&lt;/h2&gt;

&lt;p&gt;We use webpack for our build pipeline, and found out that &lt;code&gt;webpack&lt;/code&gt; was sometimes resolving modules that &lt;code&gt;tsc&lt;/code&gt; couldn’t. This is problematic, as we wanted to use &lt;code&gt;tsc&lt;/code&gt; for our CI checks! After experimentation, I found that imports must adhere to the following format:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Absolute imports from the current package must not be prefixed with the package’s name, i.e. if you are currently inside &lt;code&gt;ha-dash&lt;/code&gt; (the name of one of our sub-projects within the monorepo) you must write &lt;code&gt;import { whatever } from 'src/components&lt;/code&gt; and not &lt;code&gt;import { whatever } from 'ha-dash/src/components'&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;src&lt;/code&gt; may be skipped by setting that package’s &lt;code&gt;baseUrl&lt;/code&gt; to &lt;code&gt;src&lt;/code&gt; in its &lt;code&gt;tsconfig.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Absolute imports from other packages must be written as &lt;code&gt;{package_name}/src/some_module&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Unfortunately we haven’t found how to skip the &lt;code&gt;/src/&lt;/code&gt;  for cross-package imports yet. &lt;a href="https://github.com/nodejs/node/issues/14970#issuecomment-571887546" rel="noopener noreferrer"&gt;This solution&lt;/a&gt; seemed promising but it causes the typescript compiler to hang for some reason.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While transitioning and changing import paths, I’ve often used Linux shell loops like the following:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# make sure your current directory is the package you wish to perform changes in&lt;/span&gt;
&lt;span class="c"&gt;# commit your current repo state so you can undo in case of mistake!&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;**&lt;/span&gt;.&lt;span class="o"&gt;{&lt;/span&gt;ts,tsx&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"s?from 'survey-manager-src/?from '?g"&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;while in the &lt;code&gt;survey-manager&lt;/code&gt; directory, I ran this command to change all instances of &lt;code&gt;from 'survey-manager-src/&lt;/code&gt; to &lt;code&gt;from '&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failing tests
&lt;/h2&gt;

&lt;p&gt;We use &lt;code&gt;jest&lt;/code&gt; for tests, and found that in order for tests to work in our setup we needed each package to contain a &lt;code&gt;babel.config.js&lt;/code&gt; file including &lt;code&gt;'@babel/preset-react'&lt;/code&gt;. This may be applicable to your pipeline, too!&lt;/p&gt;

&lt;h2&gt;
  
  
  CircleCI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Saving turbo cache artifacts between builds
&lt;/h3&gt;

&lt;p&gt;Turborepo stores build artifacts at &lt;code&gt;node_modules/.cache&lt;/code&gt; in order to restore files which do not need to be rebuilt.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;caribou&lt;/span&gt;
    &lt;span class="na"&gt;resource_class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xlarge&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;attach_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;restore_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;previous-build-{{ .Branch }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;apps"&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx turbo run build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;save_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;previous-build-{{ .Branch }}&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules/.cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;persist_to_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apps/&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The important sections here are &lt;code&gt;restore_cache&lt;/code&gt; and &lt;code&gt;save_cache&lt;/code&gt;. Basically this looks for any turborepo cache saved by CircleCI named &lt;code&gt;previous-build-{name_of_current_branch}&lt;/code&gt;. Then turbo will know what packages it needs to rebuild.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;persist_to_workspace&lt;/code&gt; section is important, as it lets the next step (&lt;code&gt;deploy&lt;/code&gt;) have access to the built files.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;caribou&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;attach_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deploy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;netlify"&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./deploy.sh ${CIRCLE_BRANCH} ${CIRCLE_SHA1}&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Saving dependencies between builds
&lt;/h3&gt;

&lt;p&gt;While you are at it, you can cache npm dependencies between runs. The strategy is slightly different:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;install-deps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;caribou&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;restore_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm-deps-{{ checksum "package-lock.json" }}&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm-deps-&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Dependencies"&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;echo "Node version: $(node -v)"&lt;/span&gt;
            &lt;span class="s"&gt;echo "npm version: $(npm -v)"&lt;/span&gt;
            &lt;span class="s"&gt;npm install&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;save_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm-deps-{{ checksum "package-lock.json" }}&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;persist_to_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We use &lt;code&gt;npm-deps-{{ checksum "package-lock.json" }}&lt;/code&gt; this time, to look for cached node modules from runs of &lt;em&gt;any branch&lt;/em&gt; that had the same &lt;code&gt;package-lock.json&lt;/code&gt;. If none is found, we simply get the latest cached &lt;code&gt;node_modules&lt;/code&gt;. Then &lt;code&gt;npm install&lt;/code&gt; is run anyway, so that any missing package is added.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚠️ The netlify CLI cannot use same URL prefixes as automatic branch deployments
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/netlify/cli/issues/1984#issuecomment-862554734" rel="noopener noreferrer"&gt;https://github.com/netlify/cli/issues/1984#issuecomment-862554734&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’ve previously used automatic netlify deployments by branch, then you might be used to having URLs formatted as &lt;code&gt;{branch-name}--{site-name}.netlify.app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As soon as you’ve used this feature once, you can no longer use that subdomain with the Netlify CLI. We had to move to other prefixes using the Netlify CLI &lt;code&gt;--alias&lt;/code&gt; option. The documentation says to “avoid” using the same prefix as branch names, but doesn’t say why... now you know! &lt;a href="https://github.com/netlify/cli/issues/1984" rel="noopener noreferrer"&gt;Here is the GitHub issue about this&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Only deploying the individual apps which turbo rebuilt
&lt;/h2&gt;

&lt;p&gt;This is something which the &lt;a href="https://cli.netlify.com/commands/deploy" rel="noopener noreferrer"&gt;documentation for the netlify CLI&lt;/a&gt; doesn't tell you, so you won't find out until you actually run it: &lt;strong&gt;the netlify CLI compares the newest build's file hashes with the previous build's hashes, and requests only those files which have changed.&lt;/strong&gt; In other words, you can safely use the netlify CLI to trigger deployments of &lt;em&gt;all&lt;/em&gt; your packages, and netlify will only ever receive those files which have changed.&lt;/p&gt;

&lt;p&gt;However, if you are using something less sophisticated than netlify, here's a bash script I wrote before I realised that netlify already took care of this. This script will parse the turbo build output and only redeploy apps which turbo deemed necessary to rebuild.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Save the turbo output with this command:&lt;/span&gt;
&lt;span class="c"&gt;# $ npx turbo run build 2&amp;gt;&amp;amp;1 | tee .build_output&lt;/span&gt;

&lt;span class="nv"&gt;APPS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"blog"&lt;/span&gt; &lt;span class="s2"&gt;"client-dashboard"&lt;/span&gt; &lt;span class="s2"&gt;"admin-panel"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

deploy_app&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
  &lt;span class="c"&gt;# your deployment command here&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;app &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APPS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ./.build_output&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:build: cache miss, executing"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; deploy_app &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:build: cache bypass, force"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; deploy_app &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="c"&gt;# Uncomment the first *) line to force deployment&lt;/span&gt;
    &lt;span class="c"&gt;# *) deploy_app "$app" ;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"turbo did not rebuild &lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="s2"&gt;, not deploying."&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;And for whoever it might help, our netlify deploy function:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="c"&gt;# Those environment variables are set in CircleCI&lt;/span&gt;&lt;br&gt;
site_id_of&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;br&gt;
    &lt;/span&gt;ha-dash&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HA_DASH_NETLIFY_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;&lt;br&gt;
    fa-dash&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FA_DASH_NETLIFY_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;&lt;br&gt;
    planner&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PLANNER_NETLIFY_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;&lt;br&gt;
    survey-manager&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SURVEY_MANAGER_NETLIFY_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;esac&lt;/span&gt;&lt;br&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;deploy_app&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BRANCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"production"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;br&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;branch_option&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;else&lt;br&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;branch_option&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--alias staging-branch"&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;&lt;br&gt;
  &lt;span class="c"&gt;# --prod argument applies to staging too&lt;/span&gt;&lt;br&gt;
  npx netlify deploy &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--auth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$NETLIFY_AUTH_TOKEN&lt;/span&gt; &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
      &lt;span class="nt"&gt;--dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./apps/&lt;span class="nv"&gt;$app_name&lt;/span&gt;/build &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BRANCH&lt;/span&gt;&lt;span class="s2"&gt; deployment of &lt;/span&gt;&lt;span class="nv"&gt;$GIT_HASH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--prod&lt;/span&gt; &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--site&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;site_id_of &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$appName&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nv"&gt;$branch_option&lt;/span&gt;&lt;br&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;Do you have experience transitioning to monorepo management tools? Do you see anything we can improve? Let us know! I hope this log of some of the challenges making the transition can be helpful to some of you. Happy hacking!&lt;/p&gt;

&lt;h1&gt;
  
  
  Did you enjoy this post? We're hiring!
&lt;/h1&gt;

&lt;p&gt;We have several &lt;a href="https://caribouwealth.notion.site/Careers-at-Caribou-357783b6007f4d15bae8c7b9651cebf5" rel="noopener noreferrer"&gt;open roles&lt;/a&gt; across Ops, Design, Marketing and Engineering!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Get Paid To Work On Open Source</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Wed, 21 Jul 2021 01:37:35 +0000</pubDate>
      <link>https://dev.to/_gdelgado/get-paid-to-work-on-open-source-56en</link>
      <guid>https://dev.to/_gdelgado/get-paid-to-work-on-open-source-56en</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Cover: &lt;a href="https://unsplash.com/photos/WiONHd_zYI4"&gt;Tianyi Ma&lt;/a&gt; (Unsplash)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hey! I'm the maintainer of &lt;a href="//github.com/supermacro/neverthrow"&gt;&lt;code&gt;neverthrow&lt;/code&gt;&lt;/a&gt;; one of the more popular implementations of a &lt;code&gt;Result&lt;/code&gt; type for the TypeScript ecosystem.&lt;/p&gt;

&lt;p&gt;I am trying out a "bounty" program whereby &lt;strong&gt;I pay you&lt;/strong&gt; to fix issues or implement new features.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Is &lt;code&gt;neverthrow&lt;/code&gt; or a "&lt;code&gt;Result&lt;/code&gt; Type"?!
&lt;/h3&gt;

&lt;p&gt;For a gentle introduction about what a "&lt;code&gt;Result&lt;/code&gt; type" even is, check out my blog post on &lt;a href="https://dev.to/_gdelgado/type-safe-error-handling-in-typescript-1p4n"&gt;type-safe error handling in TypeScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's a small library, but dense with advanced concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generics&lt;/li&gt;
&lt;li&gt;Functional programming and immutability&lt;/li&gt;
&lt;li&gt;Algebraic Data Types&lt;/li&gt;
&lt;li&gt;Mapped Types and advanced typescript black magic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out &lt;a href="https://github.com/supermacro/neverthrow/issues/314"&gt;the post on GitHub&lt;/a&gt; for details on how to participate .&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>opensource</category>
      <category>functional</category>
    </item>
    <item>
      <title>Challenge: Create a `pad` function without using loops!</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Tue, 20 Apr 2021 14:28:32 +0000</pubDate>
      <link>https://dev.to/_gdelgado/challenge-create-a-pad-function-without-using-loops-2id5</link>
      <guid>https://dev.to/_gdelgado/challenge-create-a-pad-function-without-using-loops-2id5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Photo Credit: Kylie Fitts / &lt;a href="http://www.kyliefitts.com"&gt;www.kyliefitts.com&lt;/a&gt; &amp;amp; &lt;a href="https://unsplash.com"&gt;https://unsplash.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In any language, implement a function &lt;code&gt;pad&lt;/code&gt; that takes a value and conditionally pads it with &lt;code&gt;n&lt;/code&gt; number of &lt;code&gt;padding&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;padded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;👋&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;requiredLength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;padded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// --&amp;gt; ***👋&lt;/span&gt;

&lt;span class="c1"&gt;//////////&lt;/span&gt;
&lt;span class="c1"&gt;// Case 2: do not pad a value whose length is equal to `requiredLength`&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;padded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;👋👋👋👋&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;requiredLength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;padded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// --&amp;gt; 👋👋👋👋&lt;/span&gt;


&lt;span class="c1"&gt;//////////&lt;/span&gt;
&lt;span class="c1"&gt;// Case 3: do not overwrite a value that is longer than `requiredLength`&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;padded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;👋👋👋👋👋👋&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;requiredLength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;padded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// --&amp;gt; 👋👋👋👋👋👋&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Submit your solutions down below! 👇👇👇
&lt;/h4&gt;

&lt;p&gt;Remember, your solution cannot use any sort of loop construct such as &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;do&lt;/code&gt;, or &lt;code&gt;for&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;: Here is &lt;a href="https://gist.github.com/supermacro/1cdb1dbc40d3a5efa05ccd164162cc9f"&gt;my solution&lt;/a&gt; in typescript.&lt;/p&gt;

</description>
      <category>challenge</category>
      <category>functional</category>
    </item>
    <item>
      <title>Type Constraints In TypeScript</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Thu, 12 Nov 2020 16:14:04 +0000</pubDate>
      <link>https://dev.to/_gdelgado/type-constraints-in-typescript-34ek</link>
      <guid>https://dev.to/_gdelgado/type-constraints-in-typescript-34ek</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Photo credit: &lt;a href="https://unsplash.com/photos/ar2dUoleWYA"&gt;https://unsplash.com/photos/ar2dUoleWYA&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Suppose you're a back end API developer and you need a way to &lt;strong&gt;guarantee at compile time&lt;/strong&gt; that you're only sending json-serializeable data out of your API. &lt;/p&gt;

&lt;p&gt;You have a &lt;code&gt;send&lt;/code&gt; function that takes some data and sends it to a API consumer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;send&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// magic...&lt;/span&gt;
  &lt;span class="c1"&gt;// or more realistically&lt;/span&gt;
  &lt;span class="c1"&gt;// calls express' res.json() method!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you're trying to prevent a dev from trying to send the following out of your api:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;makesNoSense&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;woops!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;myDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above would be stringified (i.e. serialized) under the hood into &lt;code&gt;{ myDate: 'iso-date-string' }&lt;/code&gt;. Functions aren't part of the JSON spec and thus would be removed entirely. And &lt;code&gt;Date&lt;/code&gt;s are automatically cast to strings which is not a very efficient way of sending timestamps down the network (hint: you want unix timestamps in the form of an integer). &lt;/p&gt;

&lt;p&gt;Woops! Looks like a dev forgot to call a function and also forgot to call &lt;code&gt;Date.getTime&lt;/code&gt; 😭&lt;/p&gt;

&lt;p&gt;So how do we prevent this sort of thing?&lt;/p&gt;

&lt;h2&gt;
  
  
  Type Constraints To The Rescue
&lt;/h2&gt;

&lt;p&gt;A type constraint is a "rule" that narrows down the possibilities of what a generic type could be. &lt;/p&gt;

&lt;p&gt;For example, in the the &lt;code&gt;send&lt;/code&gt; definition above, we declared a type variable &lt;code&gt;T&lt;/code&gt; that is not constrained at all. Which is why we were able to call &lt;code&gt;send&lt;/code&gt; with values that aren't JSON serializeable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This compiles ... API would send `{}`&lt;/span&gt;
&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can thus narrow the possibilities of the generic type &lt;code&gt;T&lt;/code&gt; to allow allow JSON values as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;send&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;JSONValues&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only difference is that now we've appended &lt;code&gt;extends JSONValues&lt;/code&gt; to the type variable declaration for &lt;code&gt;T&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In plain english &lt;code&gt;T extends JSONValues&lt;/code&gt; translates to, "&lt;code&gt;T&lt;/code&gt; is a generic type that must conform to the definition of &lt;code&gt;JSONValues&lt;/code&gt;".&lt;/p&gt;

&lt;p&gt;What's &lt;code&gt;JSONValues&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;It's defined as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;JSONValues&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;JSONValues&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;JSONValues&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... Yup, this is the &lt;strong&gt;entire JSON specification&lt;/strong&gt; in 7 lines of code! 🤯&lt;/p&gt;

&lt;p&gt;Now, if I call &lt;code&gt;send(new Set([1,2,3]))&lt;/code&gt; I will get a type error. Whaaaat?!?!&lt;/p&gt;

&lt;p&gt;Now you can guarantee at compile-time that you will only send valid data to your JSON API consumers :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?#code/FAFwngDgpgBAUgZQPIDkBqBDANgVygZ2BmJgF4YA7HAWwCMoAnIkgHxnxAYEsKBzZ4mypYsAmG1oB7SVigYKYtgG8YAbQDWALnacevGAF1tiVJlwEYAX0Xxk6bHnyqDwYAGNJFDuygUAJmQwADwAKjBQAB4gvn74tqYOBAB8ABQAbtjaIQCU2gAKDJLUXPhQQcJYSWRVSmImKAB0HNx8XABmYOnY2TAA9L0+-jAgkjBthRQg4UM4+HrhERAMBPgA5DDL+A0AVvieKT3UUCAAFpJ+riQbxzgMFDAFRSVQDZsyaVApFdnA1u6e3gyWAAjIFSv4UsCAEwAZh+Hi8UyBULBMRSqjEKgoGCO2lWUloqwANDAMLwoNpoTCSSUAMLSLDaTh4SxEsSrSQnGAnKBgYY85arYAGH7AfowADu0ggcwIAEJ+SUYCUKKskdguAF6gqACKamBgSQ4GBHeTDUZubBYGANckgEJcI7mwYBM08aLkhgwIF4AD8-0R3uwqIhFCgEpgOow0QOoqAA"&gt;Live demo&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Type constraints are a very powerful way to supercharge your typescript codebases.&lt;/p&gt;

&lt;p&gt;For each generic type variable that you'd like to constrain, you would append the &lt;code&gt;extends SomeTypeName&lt;/code&gt; to the definition. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;JsonValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;FinancialData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope that helps!&lt;/p&gt;




&lt;h4&gt;
  
  
  Shameless Plug
&lt;/h4&gt;

&lt;p&gt;Liked this post?&lt;/p&gt;

&lt;p&gt;I stream functional programming, TypeScript and Elm development every Tuesday at 10am on Twitch!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twitch.tv/vimboycolor"&gt;https://www.twitch.tv/vimboycolor&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>functional</category>
    </item>
    <item>
      <title>Implement a type-safe version of Node's Promisify in 7 lines of TypeScript</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Mon, 31 Aug 2020 19:54:25 +0000</pubDate>
      <link>https://dev.to/_gdelgado/implement-a-type-safe-version-of-node-s-promisify-in-7-lines-of-code-in-typescript-2j34</link>
      <guid>https://dev.to/_gdelgado/implement-a-type-safe-version-of-node-s-promisify-in-7-lines-of-code-in-typescript-2j34</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Callback&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promisify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Callback&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callbackArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callbackArgs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out &lt;a href="https://www.loom.com/share/bc228e0dd9e548a38833fa53385db092"&gt;this video&lt;/a&gt; that demonstrates type inference in action!&lt;/p&gt;

&lt;p&gt;I'm using type-variables &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;A&lt;/code&gt; to generecally implement this function over the original function's arguments, and the callback function's arguments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercises:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Did I need to define an inline anonymous function for the second argument of &lt;code&gt;fn&lt;/code&gt;? How else could I have invoked &lt;code&gt;fn&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Note that my &lt;code&gt;Callback&lt;/code&gt; type isn't a typical error-first callback like in a lot of node APIs (this is just because the functions I'm trying to promisify aren't error-first callbacks). So I'll leave it to you as an exercise to refactor my &lt;code&gt;promisify&lt;/code&gt; function to &lt;code&gt;reject&lt;/code&gt; when an error on an error-first callback is not null ;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Introducing Elm Antd</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Sun, 05 Jul 2020 15:43:13 +0000</pubDate>
      <link>https://dev.to/_gdelgado/introducing-elm-antd-jn3</link>
      <guid>https://dev.to/_gdelgado/introducing-elm-antd-jn3</guid>
      <description>&lt;p&gt;Hey friends,&lt;/p&gt;

&lt;p&gt;I'd like to share a project I've been working on that is finally in a presentable state (but still in its infancy)!&lt;/p&gt;

&lt;p&gt;The project is called &lt;a href="https://elm-antd.netlify.app/"&gt;Elm Ant Design&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The repo can be found &lt;a href="//github.com/supermacro/elm-antd"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I built Elm Ant Design in such a way that &lt;strong&gt;it encourages contributions from all developers, even those who don't yet know Elm!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Goals
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Attain 100% feature parity with React's implementation of Ant Design (which can be found &lt;a href="https://ant.design/components/overview/"&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Create a space that allows developers of all skill levels to be able to easily contribute to an open source project

&lt;ul&gt;
&lt;li&gt;You'll see in various parts of the documentation that I make reference to contributing to the project&lt;/li&gt;
&lt;li&gt;I've also created a large list of "good first issue"s and "help wanted" tags on github (&lt;a href="https://github.com/supermacro/elm-antd/issues"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;


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

&lt;h3&gt;
  
  
  Don't Know Elm? No Problem!
&lt;/h3&gt;

&lt;p&gt;Elm is a tiny language compared to JavaScript. To learn 80% of Elm takes &lt;strong&gt;a lot&lt;/strong&gt; less time than learning 80% of JS.&lt;/p&gt;

&lt;p&gt;Secondly, there is a small portion of the code that is written in JS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Webpack configuration is in JS&lt;/li&gt;
&lt;li&gt;Visual tests using Cypress and Percy are written entirely in JS as well&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you can contribute to Elm Ant Design without even knowing Elm!&lt;/p&gt;

&lt;h4&gt;
  
  
  "But Elm is not a very popular language, why would I want to learn Elm?"
&lt;/h4&gt;

&lt;p&gt;Elm will make you a better _____ developer. Whether your main language is Python, Java, C#, JavaScript. The fact that Elm is a pure functional language means that you're forced to think in a different way about your programs. And this new mental model will help you write more predictable code in your main language - I guarantee this (I have experienced this effect first hand with my job, as I'm primarily a JS &amp;amp; TypeScript developer).&lt;/p&gt;

&lt;p&gt;I would appreciate any and all feedback!&lt;/p&gt;

</description>
      <category>elm</category>
      <category>functional</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Chaining Failable Tasks</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Sat, 07 Mar 2020 17:36:20 +0000</pubDate>
      <link>https://dev.to/_gdelgado/chaining-failable-tasks-2kj4</link>
      <guid>https://dev.to/_gdelgado/chaining-failable-tasks-2kj4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;originally posted on my &lt;a href="https://gdelgado.ca/chaining-failable-tasks.html#title"&gt;blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;This post assumes familiarity with TypeScript.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my previous post, &lt;a href="https://dev.to/_gdelgado/type-safe-error-handling-in-typescript-1p4n"&gt;Type-Safe Error Handling In TypeScript&lt;/a&gt;, I introduced a &lt;a href="https://www.npmjs.com/package/neverthrow"&gt;npm package&lt;/a&gt; to model failure at the type level.&lt;/p&gt;

&lt;p&gt;If you're not familiar with &lt;code&gt;neverthrow&lt;/code&gt;, here's a quick rundown (feel free to skip this tiny intro by clicking here):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The package introduces a functional alternative to throwing exceptions

&lt;ul&gt;
&lt;li&gt;By getting rid of &lt;code&gt;throw&lt;/code&gt;ing exceptions, you make your error handling logic pure!&lt;/li&gt;
&lt;li&gt;This is the standard approach in many other languages such as Rust, Elm and Haskell to name a few. This isn't some random wild experiment I invented.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;neverthrow&lt;/code&gt; has a &lt;code&gt;Result&lt;/code&gt; type that represents either success (&lt;code&gt;Ok&lt;/code&gt;) or failure (&lt;code&gt;Err&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Result&lt;/code&gt; is defined as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;  &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;Ok&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="nx"&gt;Err&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Ok&amp;lt;T, E&amp;gt;&lt;/code&gt;: contains the success value of type &lt;code&gt;T&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Err&amp;lt;T, E&amp;gt;&lt;/code&gt;: contains the failure value of type &lt;code&gt;E&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;Ok&lt;/code&gt; or &lt;code&gt;Err&lt;/code&gt; instances with the &lt;code&gt;ok&lt;/code&gt; and &lt;code&gt;err&lt;/code&gt; functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;neverthrow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// something awesome happend&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yesss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someAwesomeValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// moments later ...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mappedYes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;yesss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doingSuperUsefulStuff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can access the value inside of &lt;code&gt;Err&lt;/code&gt; and &lt;code&gt;Ok&lt;/code&gt; instances as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOk&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// if I didn't first call `isOk`, I would get a compilation error&lt;/span&gt;
  &lt;span class="nx"&gt;myResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// or accessing values&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isErr&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;myResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This quick rundown doesn't do the package justice, so I highly recommend you check out my &lt;a href="//{filename}2019-04-29-neverthrow.md"&gt;previous post&lt;/a&gt; that really walks you through the package.&lt;/p&gt;

&lt;p&gt;&lt;span id="main-content"&gt;...&lt;/span&gt;&lt;/p&gt;




&lt;p&gt;A while back, I got feedback (&lt;a href="https://github.com/gDelgado14/neverthrow/issues/2"&gt;link to github issue&lt;/a&gt;) from two users that this module wasn't very ergonomic when it came to &lt;code&gt;Result&lt;/code&gt;s wrapped inside of a promise.&lt;/p&gt;

&lt;p&gt;This post is dedicated to covering the problem, and the solution to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Let's suppose we're working on a project that has 3 async functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;getUserFromSessionId&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getCatsByUserId&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getCatFavoriteFoodsByCatIds&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here are the type signatures for each of these functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetUserFromSessionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionUUID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AppError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetCatsByUserId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;AppError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetCatFavoriteFoodsByCatIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;catIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Food&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;AppError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's also assume that you're a developer tasked with leveraging these functions in order to &lt;em&gt;get all of the favorite foods of all of the cats owned by a single user&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;By taking a close look at the type signatures of these functions, we can start to see how we might go about implementing our task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First call &lt;code&gt;getUserFromSession&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;then get the &lt;code&gt;User&lt;/code&gt; and use that value to call &lt;code&gt;getCatsByUserId&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;then get all of the cats (&lt;code&gt;Cat[]&lt;/code&gt;) and call &lt;code&gt;getCatFavoriteFoodsByCatIds&lt;/code&gt; by passing it an array of cat ids&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The issue is that the values we need (&lt;code&gt;User&lt;/code&gt;, &lt;code&gt;Cat[]&lt;/code&gt; and &lt;code&gt;Food[]&lt;/code&gt;) are wrapped inside of &lt;code&gt;Promise&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  First Attempt At A Solution
&lt;/h3&gt;

&lt;p&gt;Let's see how we might implement this naively.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;neverthrow&lt;/code&gt; api has a &lt;code&gt;asyncMap&lt;/code&gt; &lt;a href="https://github.com/gdelgado14/neverthrow#resultasyncmap-method"&gt;method&lt;/a&gt; and &lt;code&gt;andThen&lt;/code&gt; &lt;a href="https://github.com/gdelgado14/neverthrow#resultandthen-method"&gt;method&lt;/a&gt; that we could use to solve this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// imagine we have a sessionId already&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUserFromSessionId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// result2 is a Result&amp;lt;Result&amp;lt;Cat[]&amp;gt;, AppError&amp;gt;, AppError&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asyncMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getCatsByUserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// need to get the inner result using `andThen`&lt;/span&gt;
&lt;span class="c1"&gt;// now catListResult is Result&amp;lt;Cat[]&amp;gt;, AppError&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;catListResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;andThen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;innerResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;innerResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// result3 is&lt;/span&gt;
&lt;span class="c1"&gt;// Result&amp;lt;Result&amp;lt;Food[], AppError&amp;gt;, AppError&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;catListResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asyncMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getCatFavoriteFoodsByCatIds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// so now we need to unwrap the inner result again ...&lt;/span&gt;
&lt;span class="c1"&gt;// foodListResult is Result&amp;lt;Food[], AppError&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foodListResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;andThen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;innerResult&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;innerResult&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Holy boilerplate! That was not fun. And super cumbersome! There was a lot of legwork required to continue this chain of async &lt;code&gt;Result&lt;/code&gt; tasks.&lt;/p&gt;

&lt;p&gt;... If there were only a better way!&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Result Chains! 🔗
&lt;/h3&gt;

&lt;p&gt;Version 2.2.0 of &lt;code&gt;neverthrow&lt;/code&gt; introduces a wayyy better approach to dealing with this issue.&lt;/p&gt;

&lt;p&gt;This is what it would look like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;chain3&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;neverthrow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// foodListResult is Result&amp;lt;Food[], AppError&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foodListResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;chain3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;getUserFromSessionId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getCatsByUserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;catIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getCatFavoriteFoodsByCatIds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;catIds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;Check out the API docs &lt;a href="https://github.com/gdelgado14/neverthrow#chaining-api"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Obviously the above example is quite contrived, but I promise you that this has very practical implications. As an example, here's a snippet from my own side project where I use the &lt;code&gt;chain3&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;chain3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;validateAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sessionResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;admin&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;removePassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;sessionToken&lt;/span&gt;
    &lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are 8 different &lt;code&gt;chain&lt;/code&gt; functions, each of which only vary in their arity (the number of arguments that the functions take). &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;chain&lt;/code&gt;: takes 2 async &lt;code&gt;Result&lt;/code&gt; tasks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain3&lt;/code&gt;: takes 3 async &lt;code&gt;Result&lt;/code&gt; tasks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain4&lt;/code&gt;: takes 4 async &lt;code&gt;Result&lt;/code&gt; tasks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain5&lt;/code&gt;: etc&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain6&lt;/code&gt;: etc&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain7&lt;/code&gt;: etc&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain8&lt;/code&gt;: etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The beautiful thing about this &lt;code&gt;chain&lt;/code&gt; API is that it retains the same properties as synchronous &lt;code&gt;Result.map&lt;/code&gt; chains ... namely, these async chains short-circuit whenever something at the top of the chain results in a &lt;code&gt;Err&lt;/code&gt; value 😍&lt;/p&gt;

&lt;p&gt;A useful way to think of the &lt;code&gt;chain&lt;/code&gt; api is to think of it as the asynchronous alternative to the &lt;code&gt;andThen&lt;/code&gt; method.&lt;/p&gt;




&lt;p&gt;I've had this issue noodling in my head for a while. Eventually in that same github issue I mentioned at the top of this post, &lt;a href="https://github.com/gDelgado14/neverthrow/issues/2#issuecomment-551867175"&gt;I proposed&lt;/a&gt; an approach to chaining many async computations with a set of utility functions.&lt;/p&gt;

&lt;p&gt;Before committing to that solution, I started dogfooding this approach through my own side project. After a few days of using this &lt;code&gt;chain&lt;/code&gt; API, I concluded that it was in fact quite good and ergonomic.&lt;/p&gt;

&lt;p&gt;This API is &lt;a href="https://github.com/gDelgado14/neverthrow/blob/master/tests/index.test.ts#L235"&gt;heavily tested&lt;/a&gt; and &lt;a href="https://github.com/gDelgado14/neverthrow/blob/master/README.md#chaining-api"&gt;well-documented&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>functional</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Type-Safe Error Handling In TypeScript</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Sun, 05 May 2019 18:46:45 +0000</pubDate>
      <link>https://dev.to/_gdelgado/type-safe-error-handling-in-typescript-1p4n</link>
      <guid>https://dev.to/_gdelgado/type-safe-error-handling-in-typescript-1p4n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally posted on my &lt;a href="https://gdelgado.ca/type-safe-error-handling-in-typescript.html#title"&gt;blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We've all been there before. We write a function that has to deal with some edge case, and we use the &lt;code&gt;throw&lt;/code&gt; keyword in order to handle this situation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ResponseData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;responseBody&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ResponseBody&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeHttpRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResponseData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid string passed into `makeHttpRequest`. Expected a valid URL.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="c1"&gt;// other business logic here&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// ResponseData&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now imagine a month later, you are working on your project when you or a colleague forget to wrap &lt;code&gt;makeHttpRequest&lt;/code&gt; inside of a &lt;code&gt;try / catch&lt;/code&gt; block. &lt;/p&gt;

&lt;p&gt;Two things happen here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The compiler is no longer able to tell you whether your code is safe from runtime errors. In other words, using &lt;code&gt;throw&lt;/code&gt; is not typesafe. And is just as dangerous as &lt;code&gt;any&lt;/code&gt;. They both dilute the benefits of using TypeScript in the first place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Because neither the compiler nor the types tell you that &lt;code&gt;makeHttpRequest&lt;/code&gt; can fail (read: throw), you will eventually get a runtime error. This is a waste of time, money and happiness for everyone. People begin to ask why they're using TypeScript if the compiler isn't helping them with something so basic as adding a &lt;code&gt;try / catch&lt;/code&gt; block.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;blockquote&gt;
&lt;p&gt;How do we encode failability into the typesystem?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, let's begin by acknowledging that &lt;code&gt;throw&lt;/code&gt; is not typesafe. We must use a different approach in order to get the TypeScript compiler on our side.&lt;/p&gt;

&lt;p&gt;What if we had a &lt;code&gt;type&lt;/code&gt; or &lt;code&gt;interface&lt;/code&gt; which represented the outcome of a computation that might fail?&lt;/p&gt;

&lt;p&gt;Our type would represent two simple outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Success case: Which would return / contain contain a "success value" (i.e. &lt;code&gt;ResponseData&lt;/code&gt; in the case of &lt;code&gt;makeHttpRequest&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Failure case: Which would return / contain helpful information about &lt;strong&gt;why&lt;/strong&gt; the failure occurred&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's call our type somethething intuitive like, &lt;code&gt;Result&lt;/code&gt;. Let's call our Success variant &lt;code&gt;Ok&lt;/code&gt; and our Failure variant &lt;code&gt;Err&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thus, if we were to formalize our type into code, it would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Ok&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// contains a success value of type T&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Err&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// contains a failure value of type E&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Going back to our &lt;code&gt;makeHttpRequest&lt;/code&gt; function, we would want to encode the potential for failure into the typesystem.&lt;/p&gt;

&lt;p&gt;Thus &lt;code&gt;makeHttpRequest&lt;/code&gt; would have the following signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;makeHttpRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResponseData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the function definition would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// utility functions to build Ok and Err instances&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeHttpRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResponseData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid string passed into `makeHttpRequest`. Expected a valid URL.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="c1"&gt;// other business logic here&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// Ok(ResponseData)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course &lt;code&gt;err(new Error('...'))&lt;/code&gt; seems a little tedious. But here are some things you should know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The argument of the &lt;code&gt;err&lt;/code&gt; function must be of type &lt;code&gt;E&lt;/code&gt;, or you'll get a compile error (type mismatch) between the type inside of &lt;code&gt;err&lt;/code&gt; and the return type of &lt;code&gt;makeHttpRequest&lt;/code&gt; (where the &lt;code&gt;E&lt;/code&gt; type is represented as an &lt;code&gt;Error&lt;/code&gt; instance).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Relatedly, I just chose &lt;code&gt;Error&lt;/code&gt; as the type for &lt;code&gt;E&lt;/code&gt; for the sake of simplicity ... meaning &lt;code&gt;E&lt;/code&gt; could be anything you want! More on this in a bit!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The user of &lt;code&gt;makeHttpRequest&lt;/code&gt; can use this function without fear that it might randomly throw. No more runtime errors 🚀&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The author of the &lt;code&gt;makeHttpRequest&lt;/code&gt; function also doesn't have to worry about writing and updating documentation every time a new edge case appears that would cause the function to throw an error. All of the behaviour of the function is encoded in the return type. Relatedly, the type serves as documentation now: "&lt;code&gt;makeHttpRequest&lt;/code&gt; is an asynchronous function that can either succeed with &lt;code&gt;ResponseData&lt;/code&gt; or fail with a &lt;code&gt;Error&lt;/code&gt;."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;... "But wait, how do I get the &lt;code&gt;T&lt;/code&gt; value or &lt;code&gt;E&lt;/code&gt; value that is wrapped inside of a &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt;?"&lt;/p&gt;

&lt;p&gt;Great question. Let me show you how. We're going to use a package I made [aptly] named &lt;code&gt;neverthrow&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt; npm install neverthrow&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;neverthrow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// we'll keep this simple&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ResponseBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ResponseData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;responseBody&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ResponseBody&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeHttpRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResponseData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid string passed into `makeHttpRequest`. Expected a valid URL.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="c1"&gt;// other business logic here&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// Ok(ResponseData)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we're currently at the same place we were at with the last code snippet, except this time we're using the &lt;code&gt;neverthrow&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;If you were to read through the &lt;code&gt;neverthrow&lt;/code&gt; &lt;a href="https://github.com/gdelgado14/neverthrow#top-level-api"&gt;documentation&lt;/a&gt; you'd see that a &lt;code&gt;Result&lt;/code&gt; has a &lt;code&gt;.map&lt;/code&gt; method which takes the &lt;code&gt;T&lt;/code&gt; value inside of a &lt;code&gt;Result&lt;/code&gt; and converts it into anything you want.&lt;/p&gt;

&lt;p&gt;Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;makeHttpRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./http-api.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// unwrap the Promise&lt;/span&gt;
  &lt;span class="c1"&gt;// at this point&lt;/span&gt;
  &lt;span class="c1"&gt;// we have a Result&amp;lt;ResponseData, Error&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;makeHttpRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://jsonplaceholder.typicode.com/todos/1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;But wait, what if the result variable contains an &lt;code&gt;E&lt;/code&gt; value? in other words, it's an &lt;code&gt;Err&lt;/code&gt; instead of an &lt;code&gt;Ok&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Well, again, the docs for &lt;code&gt;neverthrow&lt;/code&gt; show you how to handle this situation too ... Just use &lt;code&gt;mapErr&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;makeHttpRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./http-api.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// unwrap the Promise&lt;/span&gt;
  &lt;span class="c1"&gt;// at this point&lt;/span&gt;
  &lt;span class="c1"&gt;// we have a Result&amp;lt;ResponseData, Error&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;makeHttpRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://jsonplaceholder.typicode.com/todos/1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapErr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorInstance&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorInstance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The most beautiful thing about &lt;code&gt;Result&lt;/code&gt;s is that &lt;strong&gt;they are chainable&lt;/strong&gt;! Here's the above code in a more realistic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;makeHttpRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./http-api.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// unwrap the Promise&lt;/span&gt;
  &lt;span class="c1"&gt;// at this point&lt;/span&gt;
  &lt;span class="c1"&gt;// we have a Result&amp;lt;ResponseData, Error&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;makeHttpRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://jsonplaceholder.typicode.com/todos/1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;result&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// do something with the success value&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapErr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorInstance&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// do something with the failure value&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;There is a lot more you can do with a &lt;code&gt;Result&lt;/code&gt; type (check out &lt;a href="https://github.com/gdelgado14/neverthrow#top-level-api"&gt;the docs&lt;/a&gt;), but &lt;code&gt;map&lt;/code&gt;ing is the most important part of the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Your Types More Intuitive
&lt;/h2&gt;

&lt;p&gt;If you start using &lt;code&gt;Result&lt;/code&gt; a lot in your return types, you might notice two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The meaning of the &lt;code&gt;Result&lt;/code&gt;s is not very clear&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example: The &lt;code&gt;Result&lt;/code&gt; of a databse query might be something like &lt;code&gt;Promise&amp;lt;Result&amp;lt;T, DbError&amp;gt;&amp;gt;&lt;/code&gt; while the &lt;code&gt;Result&lt;/code&gt; of a network call might be something like &lt;code&gt;Promise&amp;lt;Result&amp;lt;T, NetworkError&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The types are really long and verbose. For example, above we had a &lt;code&gt;Promise&amp;lt;Result&amp;lt;ResponseData, Error&amp;gt;&amp;gt;&lt;/code&gt; ... this is a somewhat intimidating type!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To solve both issues, you could leverage &lt;strong&gt;type aliases&lt;/strong&gt;! &lt;/p&gt;

&lt;p&gt;Here's an example. Instead of having a function return a generic &lt;code&gt;Result&lt;/code&gt; with a &lt;code&gt;DbError&lt;/code&gt; as the &lt;code&gt;E&lt;/code&gt; type, why not alias this type to something much more intuitive?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DbResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DbError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your function can just return &lt;code&gt;Promise&amp;lt;DbResult&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;. It's a lot more succinct!&lt;/p&gt;

&lt;p&gt;Further, your type now encodes meaning. The above type says that there's something async going on that could fail and I know that it's dealing with the database. Neat!&lt;/p&gt;

&lt;p&gt;Here's a real-world example from one of my projects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SessionManager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;DecodeResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RouteResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;handler&lt;/code&gt; is a function that does a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It does some decoding / deserializing of incoming data&lt;/li&gt;
&lt;li&gt;It then does something async which generates a &lt;code&gt;RouteResult&lt;/code&gt; with some data of type &lt;code&gt;T&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I know exactly what's going to happen by only reading the types. And the beautiful thing is that I won't ever get runtime errors because none of my code throws (and all the 3rd party libs I depend on have been wrapped to return &lt;code&gt;Result&lt;/code&gt;s as well).&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Avoid using &lt;code&gt;throw&lt;/code&gt; if you can.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users of your API are not required to &lt;code&gt;catch&lt;/code&gt; (the compiler doesn't enforce it). This means you will eventually hit a runtime error ... it's just a matter of time&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;throw&lt;/code&gt; forces you to maintain documentation which will eventually become stale&lt;/li&gt;
&lt;li&gt;If you do manage to maintain your documentation, a lot of people won't bother reading completely through the documentation, and won't realize that your functions throw in certain scenarios&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;Encode the potential for failure into your types using &lt;code&gt;Result&lt;/code&gt;s &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The types are self documenting, and they cannot become "stale"&lt;/li&gt;
&lt;li&gt;Users are given a friendly API that lets them deal with failable values in a safe way (using &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;mapErr&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There's a fully-tested and type-checked npm package for this called &lt;code&gt;neverthrow&lt;/code&gt; ... try it out!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>functional</category>
      <category>typescript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>My Over-Engineered Blogging Setup</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Mon, 08 Oct 2018 17:48:24 +0000</pubDate>
      <link>https://dev.to/_gdelgado/my-over-engineered-blogging-setup-41i0</link>
      <guid>https://dev.to/_gdelgado/my-over-engineered-blogging-setup-41i0</guid>
      <description>&lt;p&gt;Originally posted at &lt;a href="https://gdelgado.ca/my-over-engineered-blogging-setup.html#title" rel="noopener noreferrer"&gt;gdelgado.ca&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post I describe how I updated my &lt;a href="https://blog.getpelican.com/" rel="noopener noreferrer"&gt;Pelican&lt;/a&gt; blog setup.&lt;/p&gt;

&lt;p&gt;A while ago, HTTP requests to my website stopped working for some reason. It was an error with my CDN (cloudflare). This, to me, was a sign from the gods that it was time to do something unnecessarily complex to fix the problem.&lt;/p&gt;

&lt;p&gt;Seriously though; there were some things I wanted to fix for a long time that I hadn't gotten around to doing. The current CDN issue + a long weekend seemed like the right time to do this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tldr&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Created a &lt;a href="https://github.com/gDelgado14/personal-site/blob/master/Dockerfile-push" rel="noopener noreferrer"&gt;custom docker image&lt;/a&gt; with (sass + python and all the pelican dependancies)&lt;/li&gt;
&lt;li&gt;Dockerized the whole project &lt;a href="https://github.com/gDelgado14/personal-site/blob/master/Dockerfile#L1" rel="noopener noreferrer"&gt;using&lt;/a&gt; the aforementioned docker image&lt;/li&gt;
&lt;li&gt;Set up automated deploys (using &lt;a href="https://circleci.com/" rel="noopener noreferrer"&gt;CircleCI&lt;/a&gt;) to deploy the blog to &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dependency Hell
&lt;/h3&gt;

&lt;p&gt;There were some things that were bugging me about the way Pelican blogs are set up for local development. The &lt;a href="http://docs.getpelican.com/en/stable/install.html" rel="noopener noreferrer"&gt;pelican docs&lt;/a&gt; suggest that you install &lt;a href="https://virtualenv.pypa.io/en/stable/" rel="noopener noreferrer"&gt;Virtualenv&lt;/a&gt;. That worked fine until I decided I wanted a better developer experience with CSS. I switched over to SASS for my CSS, but that meant that I had to install ruby since it's a ruby gem.&lt;/p&gt;

&lt;p&gt;Ok so now I have python, virtualenv and Ruby globally installed just so that I may run the blog locally. This complicates automated deploys as well since you have to install these dependancies to ensure building the blog succeeds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker to the Rescue
&lt;/h3&gt;

&lt;p&gt;I really do not like having dependancies globally installed. So I figured this would be a fun opportunity to play around with Docker.&lt;/p&gt;

&lt;p&gt;I'll spare you all the intermediate versions of my docker setup and get to what you currently see in the repo.&lt;/p&gt;

&lt;p&gt;There are three docker-related files: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Dockerfile-push&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Dockerfile-push&lt;/code&gt; contains the instructions to create a reusable image (I reuse this image during the CI process. More on this later). This image lives at &lt;a href="https://hub.docker.com/r/giorgio14/pelican/" rel="noopener noreferrer"&gt;https://hub.docker.com/r/giorgio14/pelican/&lt;/a&gt;  ... The image is fairly large, I know. So what? Sue me.&lt;/p&gt;

&lt;p&gt;Now that I have a base image to run pelican and all its dependencies, I can create a new image from it that runs a development server. That's where &lt;code&gt;Dockerfile&lt;/code&gt; comes in. In it I: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an image &lt;code&gt;FROM&lt;/code&gt; my custom giorgio14/pelican image&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;COPY&lt;/code&gt; the relevant files and directories into the image&lt;/li&gt;
&lt;li&gt;Bind my OS's port 8080 onto the container's port 8080&lt;/li&gt;
&lt;li&gt;run a &lt;code&gt;make&lt;/code&gt; script which runs a live-reloading server on port 8080&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's just one problem. If I were to create a container from this image, the container creates copies of my files, but it doesn't link back to them. In other words; the container has its own copies that are completely unrelated to the ones on my OS. This means that in spite of having a live-reloading server that listens to file changes, no files will actually change within the container.&lt;/p&gt;

&lt;p&gt;We need &lt;a href="https://docs.docker.com/storage/volumes/" rel="noopener noreferrer"&gt;volumes&lt;/a&gt;. This is a mechanism that allows a container to have access to a host OS's files and directories. I use volumes so that I may edit anything inside the &lt;code&gt;theme&lt;/code&gt; and &lt;code&gt;content&lt;/code&gt; directories and have those changes propagate to the running docker container. Once the changes occur within the container, then the python server running inside the container can regenerate the blog and serve the updated files.&lt;/p&gt;

&lt;p&gt;For this reason, I use the &lt;code&gt;docker-compose.yml&lt;/code&gt; file. In it, there's a &lt;code&gt;volumes&lt;/code&gt; key that describes which local directories I want to mount onto the running container.&lt;/p&gt;

&lt;p&gt;Now that this is all done, I can simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And docker will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pull and generate the required images&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;make devserver PORT=8080&lt;/code&gt; (which comes from the &lt;code&gt;Dockerfile&lt;/code&gt;) inside the container&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now I have a schnazzy dev setup that does not need python, virtualenv, ruby or anything :) ... Only Docker!&lt;/p&gt;

&lt;h3&gt;
  
  
  Automated deploys
&lt;/h3&gt;

&lt;p&gt;Now that I have a reusable docker image hosted on hub.docker.com, I can leverage it to make my CI steps super easy.&lt;/p&gt;

&lt;p&gt;My goal was for my website to update on every new push to the master branch on my repo. I chose CircleCI for its brand, great documentation (took me less than a day to figure out how to use it), and free pricing 🙃.&lt;/p&gt;

&lt;p&gt;I basically just followed the documentation to connect my github repo to circle and had the "&lt;a href="https://circleci.com/docs/2.0/hello-world/" rel="noopener noreferrer"&gt;hello world&lt;/a&gt;" pipeline running shortly thereafter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gDelgado14/personal-site/tree/master/.circleci" rel="noopener noreferrer"&gt;Here&lt;/a&gt; are the relevant files associated with circle. It took me a few tries and tweaks to get the pipeline running as I wanted, so I created a bash script that allowed me to run pipelines without pushing commits to github. &lt;a href="https://circleci.com/docs/2.0/examples/" rel="noopener noreferrer"&gt;Here&lt;/a&gt;'s the relevant doc from circle.&lt;/p&gt;

&lt;p&gt;I'll mention some high-level points about the &lt;code&gt;config.yml&lt;/code&gt; file. Note that I use the custom image I made above. No need to install ruby, do apt-get, or anything. It's all just ready to go with the &lt;code&gt;pelican&lt;/code&gt; cli installed as well.&lt;/p&gt;

&lt;p&gt;Since I want to deploy to netlify, I have to install their cli. I chose their current stable cli (repo &lt;a href="https://github.com/netlify/netlifyctl" rel="noopener noreferrer"&gt;here&lt;/a&gt;) instead of their node-based one since I was familiar with it already.&lt;/p&gt;

&lt;p&gt;Then I generate a production build of the blog using &lt;code&gt;make publish&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;For the sake of future debugging I figured I would save the output of the &lt;code&gt;make publish&lt;/code&gt; command in case something strange ever occurred. Circle's UI allows me to access the zipped directory if I ever need to.&lt;/p&gt;

&lt;p&gt;Finally I deploy to netlify.&lt;/p&gt;

&lt;p&gt;I've set up a custom domain on netlify by creating a CNAME record that points to the randomly-generated netlify URL. More info here on &lt;a href="https://www.netlify.com/docs/custom-domains/" rel="noopener noreferrer"&gt;netlify&lt;/a&gt; custom domains.&lt;/p&gt;

&lt;h3&gt;
  
  
  Still to be figured out
&lt;/h3&gt;

&lt;p&gt;I really want to have comments on my website, but I definitely don't want to use Disqus. When I get a chance I'll give &lt;a href="https://staticman.net" rel="noopener noreferrer"&gt;Staticman&lt;/a&gt; a shot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://snipcart.com/blog/pelican-blog-tutorial-search-comments" rel="noopener noreferrer"&gt;Staticman + Pelican Tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... and that's it! &lt;/p&gt;

</description>
      <category>docker</category>
      <category>python</category>
      <category>tutorial</category>
      <category>ci</category>
    </item>
    <item>
      <title>Zero dependancy Pub / Sub system with PostgreSQL</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Sun, 27 May 2018 15:54:59 +0000</pubDate>
      <link>https://dev.to/_gdelgado/zero-dependancy-pub--sub-system-with-postgresql-4pi8</link>
      <guid>https://dev.to/_gdelgado/zero-dependancy-pub--sub-system-with-postgresql-4pi8</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqcc50ppxpkt5plkqk47.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqcc50ppxpkt5plkqk47.jpg" alt="Elephants"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Photo by Chen Hu on Unsplash.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://setter.com/" rel="noopener noreferrer"&gt;Setter&lt;/a&gt; we have a 2nd generation API server that handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API requests coming in from internal software&lt;/li&gt;
&lt;li&gt;API requests from our customer-facing iOS and Android applications&lt;/li&gt;
&lt;li&gt;Webhook requests from 3rd party services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is all quite typical stuff. &lt;/p&gt;

&lt;h2&gt;
  
  
  Communicating With Systems Outside Of Our Control
&lt;/h2&gt;

&lt;p&gt;In the process of handling some of these requests, we have to communicate with 3rd party services. &lt;/p&gt;

&lt;p&gt;One example being customer order approvals, in which we have to send the customer an email to confirm the order and provide a sort of feedback loop to the user.&lt;/p&gt;

&lt;p&gt;So in this case, the flow looks like: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receive API request from mobile app&lt;/li&gt;
&lt;li&gt;Process API request (which will involve make some DB inserts / updates)&lt;/li&gt;
&lt;li&gt;Dispatch API request to 3rd party email provider (in our case we use &lt;a href="http://postmarkapp.com/" rel="noopener noreferrer"&gt;Postmark&lt;/a&gt; and we highly recommend it)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By making API requests directly from our system, we've now reduced the certainty of success, and introduced incomplete states. For example, Postmark (the email service provider we use) could be down for routine maintenance, and hence a request to their service could fail at unpredictable times. This introduces an incomplete state in that the customer will never receive an email to let them know that their order was indeed processed and acknowledged.&lt;/p&gt;

&lt;p&gt;This sort of thing has happened a few times at our company.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eliminating The Dependancy on 3rd Party Services
&lt;/h2&gt;

&lt;p&gt;Currently we're undergoing an internal RFC processes to decide how we're going to decouple 3rd party services from the core of our system. &lt;/p&gt;

&lt;p&gt;I took the lead on this particular RFC (although I've had lots of guidance from my colleagues while writing it), and in this post I discuss the bulk of it.&lt;/p&gt;

&lt;p&gt;What I'm proposing at our company is that we leverage the technologies we already have (PostgreSQL &amp;amp; NodeJS) in order to not increase system complexity - as opposed to using a tool such as RabbitMQ (not to say that RabbitMQ is bad).&lt;/p&gt;

&lt;p&gt;By using PostgreSQL's &lt;code&gt;LISTEN&lt;/code&gt; / &lt;code&gt;NOTIFY&lt;/code&gt; features, you have everything you need in order to have a high-performance, fault-taulerant pub / sub system. &lt;/p&gt;

&lt;p&gt;I went ahead and created an example app that implements this system - feedback welcome!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gDelgado14/pg-pubsub" rel="noopener noreferrer"&gt;https://github.com/gDelgado14/pg-pubsub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the relevant parts of the example project (as found in the README.md):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementing the "Pub" in Pub / Sub&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;migrations&lt;/code&gt; folder contains the schemas / triggers / and SQL functions necessary to implement the publishing aspect of the system.&lt;/p&gt;

&lt;p&gt;More specifically,a &lt;code&gt;db_events&lt;/code&gt; table is created which stores messages sent into the pub sub system. Further, there is a trigger made that executes a sql function on any insertion into the &lt;code&gt;db_events&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementing the "Sub" in Pub / Sub&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Inside &lt;code&gt;src/services/client.ts&lt;/code&gt;, I use the &lt;code&gt;pg&lt;/code&gt; module to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect to the db&lt;/li&gt;
&lt;li&gt;Listen to "pub_sub" events being invoked from within postgres (which I've defined in the migrations)&lt;/li&gt;
&lt;li&gt;Invoke any asynchronous functions associated with the various events that can occur in the system.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Now you can subscribe to any event you want. You can define the events in your code. It really helps if you use a statically-typed language (which is why I implemented the example in TypeScript) so that your message payload is always consistent to the message the payload is associated to. &lt;/p&gt;

&lt;p&gt;You can see some example channel / payload combinations inside &lt;code&gt;src/services/client.ts&lt;/code&gt;. For example, if you publish an &lt;code&gt;sms&lt;/code&gt; message, the payload going in and out of the pub / sub system will always be &lt;code&gt;{ msg: 'some string' }&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Another awesome aspect of this system is that you can choose to run your subscription logic on a different machine / runtime / language. This is because it's postgres that's sending messages into the runtime. In my example I kept it simple and had both the publishing and subscribing happening in the same app, but it doesn't have to be that way if you don't want it to be! &lt;/p&gt;

&lt;h2&gt;
  
  
  Handling failure gracefully
&lt;/h2&gt;

&lt;p&gt;One thing I haven't thought enough about is how to handle message processing failures. &lt;/p&gt;

&lt;p&gt;Example: Say I publish an &lt;code&gt;email&lt;/code&gt; message into the pub / sub system and a subscriber tries to process the message by, say, sending an API request to Postmark and Postmark is down. How should I best manage this? &lt;/p&gt;

&lt;p&gt;I think implementing an exponential back-off retry might be the right approach.&lt;/p&gt;

&lt;p&gt;Would love to hear your thoughts on this! &lt;/p&gt;

</description>
      <category>distributedsytems</category>
      <category>node</category>
      <category>typescript</category>
      <category>rabbitmq</category>
    </item>
    <item>
      <title>The Economics of JS</title>
      <dc:creator>Gio</dc:creator>
      <pubDate>Tue, 03 Apr 2018 15:51:36 +0000</pubDate>
      <link>https://dev.to/_gdelgado/the-economics-of-js-182d</link>
      <guid>https://dev.to/_gdelgado/the-economics-of-js-182d</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;The democratization of the web platform has brought about an influx of JS alternatives - some of which will eventually overtake JS as the de-facto tool for writing user interfaces on the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript Has Reached Its Zenith
&lt;/h2&gt;

&lt;p&gt;It is easy to forget JS's early history. &lt;a href="https://en.wikipedia.org/wiki/JavaScript#Beginnings_at_Netscape" rel="noopener noreferrer"&gt;The language was built by one person in just a few days&lt;/a&gt; without the knowledge that the "internet browser" would eventually dominate the software landscape, thus making JS the default language for reaching millions of users. &lt;strong&gt;Economics, not JavaScript's inherent features, are what lead it to become so prominent&lt;/strong&gt;. There was no alternative way to add interactivity and delight to web pages. JS had a monopoly on front-end languages.&lt;/p&gt;

&lt;p&gt;Since its inception, JS has continued to evolve; pushing the limits of what could be accomplished while also improving the ergonomics of the language by leaps and bounds. We're spoiled in this day and age when dealing with asynchronicity, but we all remember a time when callback-hell was the norm. The barrier to creating complex apps has progressively declined.&lt;/p&gt;

&lt;p&gt;But there are only so much changes one can make, and features one can add to a language, before any &lt;a href="https://www.britannica.com/topic/diminishing-returns" rel="noopener noreferrer"&gt;additions become only marginally beneficial&lt;/a&gt;. This is simply an economic law as real as the gravitational force.&lt;/p&gt;

&lt;p&gt;I think the last game-changing update to JS was &lt;code&gt;async / await&lt;/code&gt;. Everything after that has been nice, but not revolutionary. In essence; JS will only get marginally better, but will stay fundamentally as it is for the foreseeable future.&lt;/p&gt;

&lt;p&gt;At its optimal state, JS is good to use, but it is not the tool to solve every conceivable task as &lt;a href="https://twitter.com/TheLarkInn/status/979921194467110912" rel="noopener noreferrer"&gt;some people are lead to believe&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Democratization of the Web Platform
&lt;/h2&gt;

&lt;p&gt;As JS's evolution slows down, the web platform is undergoing a democratization. You no longer need to use JavaScript to deliver a web application to your users. This was not the case at the outset of the web platform. The monopoly is no more, and the market for front-end programming languages is starting to resemble something closer to a free market; fueled by a large supply of alternative languages.&lt;/p&gt;

&lt;p&gt;Technologies such as &lt;a href="http://webassembly.org/" rel="noopener noreferrer"&gt;WebAssembly&lt;/a&gt; are opening the door to solving problems which were historically restricted to the domain of JavaScript - Languages that arguably deal much better with software complexity at a large scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Software Complexity and JS
&lt;/h2&gt;

&lt;p&gt;As JS apps got more and more ambitious, the need to manage software complexity increased. Unit tests are no longer enough. Linting is no longer enough.&lt;/p&gt;

&lt;p&gt;Out of this need, &lt;a href="https://flow.org/" rel="noopener noreferrer"&gt;Flow&lt;/a&gt; and &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; emerged to help bring typesystems into JS, and hence help increase software correctness.&lt;/p&gt;

&lt;p&gt;Herein lies a hint that we've reached the limits of JS's capabilities. We're forcing types on an untyped language. And these aren't toy projects - there's a lot of demand for this featureset; just look at the downloads per day for each of the respective npm packages.&lt;/p&gt;

&lt;p&gt;I thank the heavens for TypeScript. It has made my day job a lot less stressful. But it's not without its rough edges:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-974324130479718400-0" src="https://platform.twitter.com/embed/Tweet.html?id=974324130479718400"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-974324130479718400-0');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=974324130479718400&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The above tweet represents the TypeScript ecosystem fairly in my opinion. The sheer amount of outdated or simply improperly written types is astounding. As I mentioned in the twitter thread: I would have considered contributing to the DefinitelyTyped project but from the looks of it, I get the impression that it's a lost cause.&lt;/p&gt;

&lt;p&gt;The prolific use of &lt;code&gt;any&lt;/code&gt; in TypeScript is saddening. By using &lt;code&gt;any&lt;/code&gt; you have thrown all type safety out the window. Now you're writing a Java-esque version of JS, that has &lt;em&gt;some&lt;/em&gt; type safety but it's not guaranteed because of the &lt;code&gt;any&lt;/code&gt; escape hatch.&lt;/p&gt;

&lt;p&gt;I think this is partly because of how fast the JS ecosystem moves: For every typedef written, 3 new packages come out and one week later the aforementioned typedef becomes outdated due to a major version bump (I am only estimating, so please correct me if I am way off). With this sort of pace it's impossible to keep up. The rationale becomes, "I'll fix the types later, but for now I'll just say everything is an &lt;code&gt;any&lt;/code&gt;."&lt;/p&gt;

&lt;p&gt;Or how about this?&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;So not only are typedefs either just wrong and littered with &lt;code&gt;any&lt;/code&gt;, but they're also outdated. Sometimes by several versions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So here we are with a plethora of very large JS projects, and the current solution is to throw a type system on top of a dynamic language. This makes total sense for projects that are too large to undergo a total rewrite ... But what about all the smaller projects? Why not just use a whole other (better) language altogether?&lt;/p&gt;

&lt;h4&gt;
  
  
  A paradigm shift
&lt;/h4&gt;

&lt;p&gt;Nowadays there is lots of talk about functional programming. Many have realized the perils of object oriented architectures and we are slowly seeing a shift toward functional programming and stateless architectures.&lt;/p&gt;

&lt;p&gt;This shift isn't inherently bad for JS as it has FP features, however, most JS programmers have no idea how to code functionally.&lt;/p&gt;

&lt;p&gt;Further, much like in typescript, if you allow for escape hatches, you will use escape hatches. That is to say; if you can use a &lt;code&gt;for&lt;/code&gt; loop to get a feature out quicker than thinking ahead of time of a more functional (and longer lasting) approach, then you'll eventually succumb to the temptation. Again, this is economics at play: It's much easier to follow the path of least resistance, and writing code imperatively generally requires less consideration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving away from JS
&lt;/h2&gt;

&lt;p&gt;As mentioned above, the web platform's opening up to new languages is evidence of demand for better guarantees around software complexity.&lt;/p&gt;

&lt;p&gt;Now that there are capable alternatives to writing web applications in languages other than JS, we'll start seeing growing usage of these languages for serious projects. Most notably ReasonML within Facebook.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reasonml.github.io/" rel="noopener noreferrer"&gt;ReasonML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://elm-lang.org/" rel="noopener noreferrer"&gt;Elm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://clojurescript.org/" rel="noopener noreferrer"&gt;ClojureScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.purescript.org/" rel="noopener noreferrer"&gt;PureScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the compile-to-JS languages that I'm aware of, and I'm sure there are many more which deserve a shot-out. The point being that there is clearly a trend here. Many people are unsatisfied with JS's ability to write complex software.&lt;/p&gt;

&lt;p&gt;That's not to say you can't write complex software in JS. It's just way harder to do so.&lt;/p&gt;

&lt;p&gt;These are the sorts of things you have to deal with when writing apps in JS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No type system (and if you use Flow and TS, have fun dealing with their verbosity - not to mention the insidious usage of &lt;code&gt;any&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Quirks around the language (don't use &lt;code&gt;==&lt;/code&gt; or you'll implicitly coerce types! Don't use &lt;code&gt;arguments&lt;/code&gt; as it's not actually an array! What does &lt;code&gt;this&lt;/code&gt; mean in this context?)&lt;/li&gt;
&lt;li&gt;Highly fragmented package ecosystem. There are &lt;strong&gt;many&lt;/strong&gt; alternative packages to solving the same problem:

&lt;ul&gt;
&lt;li&gt;"Oh you want to unit test? Well, just use mocha + chai + sinon. Or alternatively Jest. Or Ava. Or Tape. Or ..."&lt;/li&gt;
&lt;li&gt;Which one is the right one? Only an expert JS dev could tell you.&lt;/li&gt;
&lt;li&gt;Now you need a bundler (Webpack is the current standard - which is a glorified compiler)&lt;/li&gt;
&lt;li&gt;Are you using CommonJS or AMD modules?&lt;/li&gt;
&lt;li&gt;Are you transpiling your code?&lt;/li&gt;
&lt;li&gt;Which version of Node are you using?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;JS is a bit of a catch 22: It's probably one of the easiest languages to get started with, however its simplicity means that it's also one of the toughest languages to master. The amount of discipline and skill required to build a healthy and maintainable codebase is testament to this.&lt;/p&gt;

&lt;p&gt;The simplicity in getting started with JS defers complexity further down the time horizon. You'll shoot yourself in the foot sooner or later because there are basically no restrictions to what you can or cannot do in the language. And then you're left staring at a cesspool of code-smells with nothing to help you.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-976836311943385088-802" src="https://platform.twitter.com/embed/Tweet.html?id=976836311943385088"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-976836311943385088-802');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=976836311943385088&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hmm, maybe JS isn't conducive to maintainability in the first place?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tell a novice JS dev, "write clean code" and let me know how that pans out. Conversely, writing in, say Elm or Rust is a lot saner. You have a compiler that &lt;strong&gt;helps you&lt;/strong&gt;. It ensures that your code will run as you intend it to and it &lt;a href="http://elm-lang.org/blog/compiler-errors-for-humans" rel="noopener noreferrer"&gt;provides you feedback as you go&lt;/a&gt;. It's materially harder to write unclean code in many other languages relative to JS.&lt;/p&gt;

&lt;p&gt;Do you want to refactor a large chunk of your JS codebase? I sure hope you have written enough unit tests and your ESLint config is there to catch other errors (so much so that you've essentially done what a compiler would have done for you out of the box).&lt;/p&gt;

&lt;h4&gt;
  
  
  NPM == jungle full unpredictable packages
&lt;/h4&gt;

&lt;p&gt;You don't need to unit test your package / library before publishing it to npm.&lt;br&gt;
You also don't have a compiler in JS to provide guarantees that the package you wrote isn't going to crash.&lt;/p&gt;

&lt;p&gt;So the packages you download from npm are basically at your own peril. This is why you need a downloads counter in npm. The logic being, "If others are downloading this package, then surely it's safe to use". But obviously this is not always the case as edge cases often take a long time to surface.&lt;/p&gt;

&lt;p&gt;This is in stark contrast to any of the package ecosystems in strictly typed languages (crates.io, Hackage, Elm-Package, etc...). You don't need a downloads counter because you know the package had to be compiled before even landing on the package ecosystem. Consider pre-upload compilation a sort of litmus test which sets a consistent expectation of quality across the board.&lt;/p&gt;

&lt;p&gt;Another benefit with these other languages is that they are sustained by communities consisting of very skilled developers (the influx of devs coming from code bootcamps doesn't help alleviate the code quality problem plaguing npm). That's not to say that you don't have amazing devs in JS-land (you do), but the distribution of talent in JS has a massive standard deviation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Equilibrium in the Web Platform
&lt;/h2&gt;

&lt;p&gt;In the back-end ecosystem, there is complete freedom to choose whichever language best solves the task at hand. There is no monopoly unlike the front-end world. But I've mentioned already, this is no longer the case, and over time, we will see the advent of incredibly large and complex front-end applications built without JS (or with JS as a minor component to the app: Much like the concept of &lt;a href="https://guide.elm-lang.org/interop/javascript.html" rel="noopener noreferrer"&gt;ports in Elm&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This is known as &lt;a href="https://en.wikipedia.org/wiki/Economic_equilibrium" rel="noopener noreferrer"&gt;equilibrium in economics&lt;/a&gt; and it's about time we reached it in the front end development ecosystem.&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>elm</category>
      <category>reason</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
