<?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: Sergey Samokhov</title>
    <description>The latest articles on DEV Community by Sergey Samokhov (@hoichi).</description>
    <link>https://dev.to/hoichi</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%2F101407%2F804918ed-3d71-4afe-a2ae-e63ff1e85f5f.jpeg</url>
      <title>DEV Community: Sergey Samokhov</title>
      <link>https://dev.to/hoichi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hoichi"/>
    <language>en</language>
    <item>
      <title>be-good: Simple and Flexible Data Decoders for TypeScript</title>
      <dc:creator>Sergey Samokhov</dc:creator>
      <pubDate>Wed, 24 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/hoichi/be-good-simple-and-flexible-data-decoders-for-typescript-2ejk</link>
      <guid>https://dev.to/hoichi/be-good-simple-and-flexible-data-decoders-for-typescript-2ejk</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;This post introduces both JSON decoders and my humble library of decoder building blocks, called &lt;a href="https://github.com/hoichi/be-good"&gt;&lt;code&gt;be-good&lt;/code&gt;&lt;/a&gt;. Let’s start with the first.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Decoders And Why Do We Need Them
&lt;/h2&gt;

&lt;p&gt;JSON decoders are well known in statically typed languages like Elm or ReasonML (and are probably older than those two). Static types are a great way to catch many bugs at compilation time, which is sweet when the alternative is chasing those bugs in production. And even when it comes to &lt;em&gt;preventing&lt;/em&gt; bugs, static types have some advantages over other techniques. I won’t discuss types vs. tests here, tempted as I am, but defensive programming is obviously wordier (thus obscuring business logic and creates more places for bugs to hide) and has some runtime cost.&lt;/p&gt;

&lt;p&gt;But of course, even the most sound type system keeps you safe only if it controls the whole data lifecycle, cradle to grave. If the data comes from the outside world (say, across the network), what can the compiler say? If your types suggest a request returns data of type &lt;code&gt;{ status: Status, data: Data }&lt;/code&gt; but instead you get &lt;code&gt;{ status: -1, error: {}}&lt;/code&gt;, not only can your code break in runtime; it can also bring down your whole app exactly &lt;em&gt;because&lt;/em&gt; you thought you didn’t need no stinking defensive programming any more, and now your code has no immunity.&lt;/p&gt;

&lt;p&gt;Sure, there are situations where you can trust your types for external data, e.g., whey you generate them from a Swagger or a GraphQL schema. If you have something like that, and your DevOps scenarios are sound, you probably don’t need decoders—congrats, godspeed, carry on.&lt;/p&gt;

&lt;p&gt;But maybe you don’t have that luxury. Perhaps you have a lot of legacy back-end, or it’s some tool developed by a single intern with no notion of what REST is, or the API is third-party. There are plenty of reasons you might have zero control over the API, and so typegen may be out of the question. Or maybe your app is just too small to bother, or you hate modern tooling and generally can’t be arsed.&lt;/p&gt;

&lt;p&gt;Whatever your reasons, decoders may be of use. Let’s start with a (very loose) definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A decoder is a function that takes some external data that could be anything and makes sure it &lt;em&gt;is&lt;/em&gt; of the type it’s supposed to be.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Enter &lt;code&gt;be-good&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;But enough of theory, let’s see some code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;be&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;beObjectOf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be-good&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isString&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;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;optional&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;surname&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;middleName&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userDecoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;beObjectOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;beString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;beString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;middleName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beString&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;// typeof userDecoder === (x: unknown) =&amp;gt; User | null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here’s how it treats various inputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;userDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// null: not an object&lt;/span&gt;
&lt;span class="nx"&gt;userDecoder&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt; &lt;span class="c1"&gt;// null: missing some properties&lt;/span&gt;
&lt;span class="nx"&gt;userDecoder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// wrong property types&lt;/span&gt;
&lt;span class="nx"&gt;userDecoder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jackie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Chan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// { name: 'Jackie', surname: 'Chan' } (middleName is optional)&lt;/span&gt;
&lt;span class="nx"&gt;userDecoder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Samuel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;middleName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;L.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jackson&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// { name: 'Samuel', middleName: 'L.' surname: 'Jackson' }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you see, its runtime behavior is true to its signature: whatever the input, it returns either a value of type &lt;code&gt;User&lt;/code&gt;, or &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic building block: &lt;code&gt;be&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Immoral though it might sound, the most important part of &lt;code&gt;be-good&lt;/code&gt; is &lt;code&gt;be&lt;/code&gt;. &lt;code&gt;be&lt;/code&gt; is a &lt;em&gt;decoder factory&lt;/em&gt;, i.e., it &lt;em&gt;creates decoders&lt;/em&gt;. Its signature looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;be&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;predicate&lt;/span&gt;&lt;span class="p"&gt;:&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="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;is&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;Decoder&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;a is T&lt;/code&gt; part is crucial: the factory &lt;code&gt;be&lt;/code&gt; takes a &lt;a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards"&gt;user-defined type guard&lt;/a&gt;. Happily, functions like &lt;code&gt;lodash/isString&lt;/code&gt; or those in &lt;a href="https://www.npmjs.com/package/@types/check-types"&gt;check-types&lt;/a&gt; are typed exactly like that. And later in this post, we’ll see how to roll your own.&lt;/p&gt;

&lt;p&gt;What does &lt;code&gt;be&lt;/code&gt; return? Given a predicate asserting that &lt;code&gt;a is T&lt;/code&gt;, &lt;code&gt;be&lt;/code&gt; returns &lt;code&gt;Decoder&amp;lt;T&amp;gt;&lt;/code&gt;, i.e., &lt;code&gt;(x: unknown) =&amp;gt; T&lt;/code&gt;. So, whenever the predicate returns &lt;code&gt;true&lt;/code&gt;, the resulting decoder returns a value of type &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;“But what if the predicate returns &lt;code&gt;false&lt;/code&gt;?!”—an acute reader might cry in alarm. In that case, since the return type only allows values of type &lt;code&gt;T&lt;/code&gt; and the input is quite obviously &lt;em&gt;not&lt;/em&gt; of type &lt;code&gt;T&lt;/code&gt;, the decoder has literally no other recourse but to &lt;em&gt;throw a bloody exception&lt;/em&gt;. E.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;beString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 'foo'&lt;/span&gt;
&lt;span class="nx"&gt;beString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// throws&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Catching decorators: &lt;code&gt;or&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;So, decoders can throw. One way to deal with that is to let whole parts of your application fail and show some fallback UI, e.g., using React’s &lt;a href="https://reactjs.org/docs/error-boundaries.html"&gt;error boundaries&lt;/a&gt;. This approach makes sense, but there are cases to be made for catching decoding exceptions closer to its source.&lt;/p&gt;

&lt;p&gt;One of those cases is some data can be quite optional, as we’ve seen with &lt;code&gt;middleName&lt;/code&gt; above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;optional&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;beObjectOf&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;beString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;surname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;beString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;middleName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;No need to invalidate a whole user because she doesn’t have a middle name.&lt;/p&gt;

&lt;p&gt;Another case is when you validate/invalidate your data rather far from the code that displays any UI (e.g., you put the decoded data in a Redux store and then update your components with it). Then it makes sense to express invalidity of&lt;br&gt;&lt;br&gt;
the data with… well, data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;optional&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beObjectOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*...*/&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// unknown -&amp;gt; (User | null)&lt;/span&gt;

&lt;span class="c1"&gt;// somewhere in JSX&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;section&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserInfo&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="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A third case is a default value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orZero&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beSum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;orZero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beNumber&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// unknown -&amp;gt; (number)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you’ve probably divined from the examples above, &lt;code&gt;or&lt;/code&gt; accepts a fallback&lt;br&gt;&lt;br&gt;
value and returns a decorator function. Decorator is then applied to a decoder&lt;br&gt;&lt;br&gt;
and, being a decorator, returns a new decoder. That new decoder never throws:&lt;br&gt;&lt;br&gt;
when the input data is invalid, it returns the fallback value instead. In a&lt;br&gt;&lt;br&gt;
bastardized semi-haskellish type notation, its signature is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Fb&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;In&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;In&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Out&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Fb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Put another way, when the original decoder returns values of type &lt;code&gt;A&lt;/code&gt;, and the fallback value you give to &lt;code&gt;or&lt;/code&gt; is of type &lt;code&gt;B&lt;/code&gt;, the resulting (decorated)&lt;br&gt;&lt;br&gt;
decoder returns values of type &lt;code&gt;A | B&lt;/code&gt;. &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; can differ (e.g., you can use nullish—or any other values to signal invalid/missing data) or they can coincide (e.g., when a fallback is just a default value). This (as many other things with be-good) is totally up to the consumer.&lt;/p&gt;
&lt;h2&gt;
  
  
  Decoding objects, arrays, and dictionaries
&lt;/h2&gt;

&lt;p&gt;You have already seen &lt;code&gt;beOjectOf&lt;/code&gt; in action: it checks if the input is an object, and then it validates the object properties, it’s rather self-explanatory. Let’s move on to collections, e.g., arrays and dictionaries. For that, we have two other factories.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;beArrayOf&lt;/code&gt; and &lt;code&gt;beDictOf&lt;/code&gt; are similar to &lt;code&gt;beObjectOf&lt;/code&gt;, but their parameters are a bit different. First, they take a single element decoder—meaning all the elements are supposed to be of the same type. Second, the factory can optionally take a config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BeCollectionOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/** What to invalidate on errors: one element or the whole collection */&lt;/span&gt;
  &lt;span class="nx"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;single&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="cm"&gt;/** Minimum count of (valid) collection elements */&lt;/span&gt;
  &lt;span class="nx"&gt;minSize&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Some examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;beArrayOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beNumber&lt;/span&gt;&lt;span class="p"&gt;)([&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;25.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;// [3, 25.4, -7], because by default, `invalidate` option is 'singe',&lt;/span&gt;
&lt;span class="c1"&gt;// and that means simply omitting invalid elements&lt;/span&gt;

&lt;span class="nx"&gt;beArrayOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})([&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;25.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;// throws on reaching the first bad element&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orFallback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;fallback&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="nx"&gt;beArrayOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orFallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beNumber&lt;/span&gt;&lt;span class="p"&gt;))([&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;25.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;// [3, 25.4, '&amp;lt;fallback&amp;gt;', -7], compare to the first example&lt;/span&gt;

&lt;span class="nx"&gt;beArrayOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;})([&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;25.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;// throws: only 3 valid elements&lt;/span&gt;

&lt;span class="cm"&gt;/* beDictOf works pretty similarly, and in fact, takes the same options */&lt;/span&gt;

&lt;span class="nx"&gt;beDictOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beNumber&lt;/span&gt;&lt;span class="p"&gt;)({&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;25.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// { a: 3, b: 25.4, d: -7 }&lt;/span&gt;
&lt;span class="c1"&gt;// etc...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Decoding nested structures
&lt;/h3&gt;

&lt;p&gt;Since &lt;code&gt;beObjectOf&lt;/code&gt;, &lt;code&gt;beArrayOf&lt;/code&gt;, and &lt;code&gt;beDictOf&lt;/code&gt; take other decoders, they can also take the object/collection decoders, meaning you can nest them if necessary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beNestedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;beObjectOf&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;beArrayOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beObjectOf&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;beNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;dict1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;beDictOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beNumber&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;dict2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt;&lt;span class="p"&gt;({})(&lt;/span&gt;&lt;span class="nx"&gt;beDictOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beString&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;Mind where you catch though: if you don’t use &lt;code&gt;or&lt;/code&gt;—and you use &lt;code&gt;invalidate: ‘all’&lt;/code&gt; a lot, a single wrong property can invalidate your whole structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  A note on generics and type inference
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;beObjectOf&lt;/code&gt; and it’s brethern are generic, but you don’t have to spell out &lt;code&gt;beObjectOf&amp;lt;Foo&amp;gt;&lt;/code&gt; all the time. The decoder return type will be inferred from the property decoders you gave to &lt;code&gt;beObjectOf&lt;/code&gt;: e.g.&lt;br&gt;&lt;br&gt;
&lt;code&gt;beObjectOf({ a: beString })&lt;/code&gt; will have type &lt;code&gt;(x: unknown) =&amp;gt; { a : string }&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
And since TypeScript types are structural, it doesn’t matter how the type is&lt;br&gt;&lt;br&gt;
called as long as the shape is right.&lt;/p&gt;

&lt;p&gt;But if you make a mistake in a property name or a kind of decoder you give to &lt;code&gt;beObjectOf&lt;/code&gt;, TypeScript &lt;em&gt;will&lt;/em&gt; fail—somewhere—and the error message might point to a place far from where the actual error is, and you’ll spend more time fixing it. It might be better to specify the expected type right inside a decoder (like above), or maybe right outside of it, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;beOjbectOf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Decoder&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;be-good&lt;/span&gt;&lt;span class="dl"&gt;'&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;objDecoder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Decoder&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beObjectOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Fail early, I say.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom predicates and custom decoders
&lt;/h2&gt;

&lt;p&gt;I think that’s quite enough for one post already (finish early, I say), but I must mention an essential design goal of &lt;code&gt;be-good&lt;/code&gt;: being flexible. Indeed, it’s more flexible than the above examples might suggest. For one thing, the type guards from Lodash are handy, but what if you want to check for more?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isEven&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beEven&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isEven&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// unknown =&amp;gt; number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you dig opaque types, you can use those too (the enum trick is from&lt;br&gt;&lt;br&gt;
&lt;a href="https://spin.atomicobject.com/2017/06/19/strongly-typed-date-string-typescript/"&gt;an article by Patrick Bacon&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;PriceBrand&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Price&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;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;PriceBrand&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;Price&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bePrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isPrice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// unknown =&amp;gt; Price&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can also write whole custom decoders, be it because you cannot validate&lt;br&gt;&lt;br&gt;
fields separately, or because you need to &lt;del&gt;mess with&lt;/del&gt; manipulate your data&lt;br&gt;&lt;br&gt;
structure. Enter two low-level helpers: &lt;code&gt;beObject&lt;/code&gt; (not to be confused with&lt;br&gt;&lt;br&gt;
&lt;code&gt;beObjectOf&lt;/code&gt;) and &lt;code&gt;fail&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;be&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;beObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be-good&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;rangeDecoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)((&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Range&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;// note that `start` and `end` are the properties of the input, not of the output&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;beObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// typeof start === typeof end === unknown&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;fail&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 range&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;end&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;Note how the earlier examples mostly compose functions, but as you see here,&lt;br&gt;&lt;br&gt;
that’s not the only resource you have. Sure, here we still use a catching&lt;br&gt;&lt;br&gt;
decorator™ (i.e., the result of &lt;code&gt;or(null)&lt;/code&gt;), which counts as functional&lt;br&gt;&lt;br&gt;
composition. But you can also create variables, fail the decoder imperatively&lt;br&gt;&lt;br&gt;
and do all the stuff you typically do in JavaScript—even though I don’t&lt;br&gt;&lt;br&gt;
recommend side effects in your decoders. And sure, you could write this&lt;br&gt;&lt;br&gt;
particular decoder in a more functional fashion, but the point is you don’t have&lt;br&gt;&lt;br&gt;
too. &lt;code&gt;be-good&lt;/code&gt; is not hellbent on forcing one specific programming style.&lt;/p&gt;

&lt;p&gt;Another important thing is using &lt;code&gt;fail&lt;/code&gt; to… well, fail the decoder. Notice&lt;br&gt;&lt;br&gt;
how, like &lt;code&gt;beObject&lt;/code&gt;, &lt;code&gt;fail&lt;/code&gt; is used inside a function wrapped in a catching&lt;br&gt;&lt;br&gt;
decorator. You don’t want unchecked exceptions everywhere. And while on the one&lt;br&gt;&lt;br&gt;
hand, you have to remember that decoders use exceptions under the hood (and may&lt;br&gt;&lt;br&gt;
blow that hood if you don’t pay attention), on the other hand, it’s not a good&lt;br&gt;&lt;br&gt;
idea to throw exceptions manually. If you want to fail your decoder, call&lt;br&gt;&lt;br&gt;
&lt;code&gt;fail&lt;/code&gt;. So far, it doesn’t do much besides throwing, but it might in the future,&lt;br&gt;&lt;br&gt;
so don’t break the abstraction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Left unsaid
&lt;/h2&gt;

&lt;p&gt;I don’t believe &lt;code&gt;be-good&lt;/code&gt; is complete: it misses mechanisms for decoding sum types (unions), proper docs, type tests, and maybe it needs better error messages (file an issue if you think it does). I also probably haven’t done writing about it. What’s left unsaid is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;design goals&lt;/li&gt;
&lt;li&gt;comparison to known alternatives (see &lt;a href="https://github.com/gcanti/io-ts"&gt;gcanti/io-ts&lt;/a&gt; &amp;amp; &lt;a href="https://github.com/nvie/decoders"&gt;nvie/decoders&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;comparing &lt;code&gt;null(ish) | Entity&lt;/code&gt; with monadic types like &lt;code&gt;Result&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;advanced composability of decoders&lt;/li&gt;
&lt;li&gt;why the hell the functions are not curried&lt;/li&gt;
&lt;li&gt;and so probably on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the meantime, &lt;a href="https://github.com/hoichi/be-good#installation"&gt;try be-good&lt;/a&gt;, play with it, file some issues, maybe even contribute if you like, and stay safe.&lt;/p&gt;




&lt;p&gt;Posted first at &lt;a href="https://hoichi.io"&gt;hoichi.io&lt;/a&gt;, narcissist that I am.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>json</category>
      <category>decoder</category>
      <category>project</category>
    </item>
    <item>
      <title>Simple Sum Types In TypeScript Without Common Fields</title>
      <dc:creator>Sergey Samokhov</dc:creator>
      <pubDate>Fri, 05 Jun 2020 11:53:00 +0000</pubDate>
      <link>https://dev.to/hoichi/simple-sum-types-in-typescript-without-common-fields-3jn9</link>
      <guid>https://dev.to/hoichi/simple-sum-types-in-typescript-without-common-fields-3jn9</guid>
      <description>&lt;p&gt;&lt;a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions"&gt;Discriminated unions&lt;/a&gt; are well known in TypeScript. Their only (?) downside is they need a common property usually named &lt;code&gt;kind&lt;/code&gt; or &lt;code&gt;tag&lt;/code&gt;, e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RenderProps&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="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;children&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="nx"&gt;ReactElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;render&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="nx"&gt;ReactElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

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



&lt;p&gt;Which makes it a tad too wordy to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RPComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RenderProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;children&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;render&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&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;// elsewhere&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RPComponent&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;render&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i&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;n&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/i&amp;gt;} /&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, I’m fine with JS in templates (if you still call of JSX as of templates, and why not), but that unnecessary &lt;code&gt;kind&lt;/code&gt; prop gets my goat.&lt;/p&gt;

&lt;p&gt;So here’s a more compact solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RenderProps&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="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="nx"&gt;ReactElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;render&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="nx"&gt;ReactElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RPComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RenderProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// and&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RPComponent&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i&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;n&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/i&amp;gt;} /&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;It’s still a sum type (you can neither omit both &lt;code&gt;children&lt;/code&gt; and &lt;code&gt;render&lt;/code&gt; nor provide them both), but now you don’t need no stinking &lt;code&gt;kind&lt;/code&gt; anywhere.&lt;/p&gt;

&lt;p&gt;Mind that for some reason it’s not enough to declare the union variants as &lt;code&gt;{ chidlren: SomeType, render: undefined }&lt;/code&gt;. At least for JSX, TypeScript will want you to still &lt;em&gt;specify&lt;/em&gt; a prop and give it a value of &lt;code&gt;undefined&lt;/code&gt;. But &lt;code&gt;render?: undefined&lt;/code&gt; (or &lt;code&gt;never&lt;/code&gt;, which, I think, better conveys your intention) does the trick.&lt;/p&gt;




&lt;p&gt;Posted first at &lt;a href="https://hoichi.io"&gt;hoichi.io&lt;/a&gt;, because you can’t be too paranoid.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>types</category>
      <category>react</category>
      <category>tips</category>
    </item>
    <item>
      <title>Real-World Composable Error Handling in Reason</title>
      <dc:creator>Sergey Samokhov</dc:creator>
      <pubDate>Sat, 21 Dec 2019 11:53:00 +0000</pubDate>
      <link>https://dev.to/hoichi/real-world-composable-error-handling-in-reason-3eah</link>
      <guid>https://dev.to/hoichi/real-world-composable-error-handling-in-reason-3eah</guid>
      <description>&lt;h2&gt;
  
  
  The Question
&lt;/h2&gt;

&lt;p&gt;If you’ve ever considered handling errors in Reason or OCaml, chances are, you’ve happened upon &lt;a href="http://keleshev.com/composable-error-handling-in-ocaml"&gt;Vladimir Keleshev’s article&lt;/a&gt;. Everybody links to it, so it seems like &lt;em&gt;the&lt;/em&gt; way to handle errors.&lt;/p&gt;

&lt;p&gt;But how does it look in practice?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Experiment
&lt;/h2&gt;

&lt;p&gt;Let’s try and write a simple &lt;code&gt;useFetch&lt;/code&gt;, a custom &lt;a href="https://reasonml.github.io/reason-react/docs/en/components#hooks"&gt;ReasonReact hook&lt;/a&gt; that wraps &lt;a href="https://github.com/reasonml-community/bs-fetch"&gt;bs-fetch&lt;/a&gt;. Then we’ll use another dependency, for decoding. And — the whole purpose for this experiment — we’ll try to compose their errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using bs-fetch
&lt;/h2&gt;

&lt;p&gt;Let’s start with the basics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// UseFetch.re

type fetchError = [| `FetchError(Js.Promise.error)];

type t =
  | Fetching
  | Complete(Belt.Result.t(Js.Json.t, fetchError));

let useFetch = url =&amp;gt; {
  let (state, setState) = React.useState(_ =&amp;gt; Fetching);

  React.useEffect1(
    () =&amp;gt; {
      Js.Promise.(
        Fetch.fetch(url)
        |&amp;gt; then_(Fetch.Response.json)
        |&amp;gt; then_(json =&amp;gt; setState(_ =&amp;gt; Complete(Ok(json))) |&amp;gt; resolve)
        |&amp;gt; catch(error =&amp;gt;
             `FetchError(error)
             |&amp;gt; (error =&amp;gt; setState(_ =&amp;gt; Complete(Error(error))) |&amp;gt; resolve)
           )
        |&amp;gt; ignore
      );

      None;
    },
    [|url|],
  );

  state;
};

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



&lt;p&gt;First, let’s check if it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[@react.component]
let make = () =&amp;gt; {
  let reposJson =
    UseFetch.useFetch(
      "https://api.github.com/search/repositories?q=language:reason&amp;amp;sort=stars&amp;amp;order=desc",
    );

  Js.log(reposJson);

  ReasonReact.string("Fetching...");
};

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



&lt;p&gt;It does work, as in, it logs some JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  bs-fetch Error
&lt;/h2&gt;

&lt;p&gt;Now let’s talk about error handling. Note how &lt;code&gt;fetchError&lt;/code&gt; has only one variant because bs-fetch uses &lt;code&gt;Js.Promise.error&lt;/code&gt; for everything, and &lt;code&gt;Js.Promise.error&lt;/code&gt; is &lt;a href="https://reasonml.chat/t/how-do-i-allow-consumers-of-promise-catch-the-errors/136/4"&gt;opaque by design&lt;/a&gt;. The thing is, you can technically throw anything in JS, not just an exception. If that worries you, run before it gets worse: the upcoming React &lt;a href="https://reactjs.org/docs/concurrent-mode-suspense.html"&gt;Suspense for Data Fetching in React&lt;/a&gt; is officially supposed to throw promises &lt;a href="https://overreacted.io/algebraic-effects-for-the-rest-of-us/"&gt;by way of algebraic effects&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;So here’s one spanner in the works: opaque types in underlying libs. We sort of know that what bs-fetch happens to throw &lt;em&gt;are&lt;/em&gt; exceptions, so we could use &lt;a href="https://bucklescript.github.io/docs/en/intro-to-external.html#special-identity-external"&gt;magic&lt;/a&gt; to convert &lt;code&gt;Js.Promise.error&lt;/code&gt;, and then extract the message, but even if we &lt;em&gt;were&lt;/em&gt; to parse error messages, what good is that? Parsing messages is heuristic and, therefore, brittle, and using them raw is only any good for technical purposes, like logging, not for anything user-facing.&lt;/p&gt;

&lt;p&gt;But speaking of logging, we didn’t fetch JSON just to dump it it to console. Let’s decode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decoding
&lt;/h2&gt;

&lt;p&gt;Of all the Reason json decoders I know, &lt;a href="https://github.com/reasonml-labs/decco"&gt;decco&lt;/a&gt; is by far the most sugary, using ppx to create decoders from annotated type definitions. Here’s how it looks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// GhRepo.re
[@decco]
type repo = {
  [@decco.key "full_name"]
  fullName: string,
  [@decco.key "html_url"]
  htmlUrl: string,
};
[@decco]
type t = {items: array(repo)};

// Decode.re
type decodeError = [| `DecodeError(Decco.decodeError)];

// wrapping Decco.decodeError in a polymorphic variant
let mapDecodingError =
  fun
  | Ok(x) =&amp;gt; Ok(x)
  | Error(e) =&amp;gt; Error(`DecodeError(e));

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



&lt;p&gt;&lt;code&gt;Decco.decodeError&lt;/code&gt; is not as opaque: it’s defined as a record, holding path, error message, and JSON value. Still, to discern various errors, we’d have to resort to parsing messages just the same; let’s not.&lt;/p&gt;

&lt;p&gt;To make composing with decoders easier, let’s also create a helper in the &lt;code&gt;UseFetch&lt;/code&gt; module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let mapOk = (t, f) =&amp;gt;
  switch (t) {
  | Fetching =&amp;gt; Fetching
  | Complete(Ok(r)) =&amp;gt; Complete(f(r))
  | Complete(Error(_)) as e =&amp;gt; e
  };

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



&lt;p&gt;&lt;code&gt;UseFetch.mapOk&lt;/code&gt; is similar to &lt;code&gt;Result.flatMap&lt;/code&gt;: the function parameter that it takes can return either &lt;code&gt;Ok(data)&lt;/code&gt; or &lt;code&gt;Error(error)&lt;/code&gt;—exactly the signature of Decco decoders.&lt;/p&gt;

&lt;p&gt;All together now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// App.re
[@react.component]
let make = () =&amp;gt; {
  let repos =
    UseFetch.(
      useFetch(
        "https://api.github.com/search/repositories?q=language:reason&amp;amp;sort=stars&amp;amp;order=desc",
      )
      -&amp;gt;mapOk(r =&amp;gt; GhRepo.t_decode(r)-&amp;gt;Decode.mapDecodingError)
    );

  ReasonReact.string("Fetching...");
};

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



&lt;p&gt;But lo, an error.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Decoding Error, or, Parametrizing UseFetch.mapOk
&lt;/h2&gt;

&lt;p&gt;Immediately we get an error somewhere inside that &lt;code&gt;mapOk&lt;/code&gt; call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  This has type:
    result(Js.Array.t(GhRepo.t), ([&amp;gt; `DecodeError(Decco.decodeError)] as 'a))
      (defined as Belt_Result.t(Js.Array.t(GhRepo.t), 'a))
  But somewhere wanted:
    Belt.Result.t(Js.Json.t, UseFetch.fetchError) (defined as
      Belt_Result.t(Js.Json.t, UseFetch.fetchError))

  The incompatible parts:
    Js.Array.t(GhRepo.t) (defined as array(GhRepo.t))
    vs
    Js.Json.t (defined as Js.Json.t)

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



&lt;p&gt;I won’t pretend I understood this error right off the bat, but neither will I burden you with the story of my googling. The culprit is the way that &lt;code&gt;UseFetch.mapOk&lt;/code&gt; is defined: our decoding process yields decoded data and a decoding error (typed as a superset of the same error), but &lt;code&gt;mapOk&lt;/code&gt; expects strictly &lt;code&gt;Js.Json.t&lt;/code&gt; and &lt;code&gt;fetchError&lt;/code&gt;. So we need to parametrize both, and we start by parametrizing &lt;code&gt;UseFetch.t&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type t('d, 'e) =
  | Fetching
  | Complete(result('d, [&amp;gt; fetchError] as 'e));

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



&lt;p&gt;And luckily, that’s the only place you have to introduce type parameters. You don’t have to provide &lt;code&gt;'d&lt;/code&gt; or &lt;code&gt;'e&lt;/code&gt; when consuming those types, nor do you have to specify the &lt;code&gt;mapOk&lt;/code&gt; signature, because OCaml/Reason type inference is pretty great. If you &lt;em&gt;had&lt;/em&gt; to provide the signature, it’d look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let mapOk: 'a 'b 'e. (t('a, 'e), 'a =&amp;gt; result('b, 'e)) =&amp;gt; t('b, 'e) =
  (t, f) =&amp;gt;
    switch (t) {
    | Fetching =&amp;gt; Fetching
    | Complete(Ok(r)) =&amp;gt; Complete(f(r))
    | Complete(Error(_)) as e =&amp;gt; e
    };

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



&lt;p&gt;As you can see, there are two type parameters for data, &lt;code&gt;'a&lt;/code&gt; &amp;amp; &lt;code&gt;'b&lt;/code&gt;, because obviously, the mapping function can, and usually will, convert data from one type to another (e.g., from JSON to a record). But the error type stays the same because unifying an error type is precisely what we’re after. And again, let me remind you we don’t actually have to spell out the &lt;code&gt;mapOk&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;Anyway, here we are, consuming the decoded result and the possible errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[@react.component]
let make = () =&amp;gt; {
  UseFetch.(
    useFetch(
      "https://api.github.com/search/repositories?q=language:reason&amp;amp;sort=stars&amp;amp;order=desc",
    )
    -&amp;gt;mapOk(r =&amp;gt; GhRepo.t_decode(r)-&amp;gt;Decode.mapDecodingError)
    -&amp;gt;(
        fun
        | Fetching =&amp;gt; ReasonReact.string("Fetching...")
        | Complete(Ok(({items}: GhRepo.t))) =&amp;gt;
          &amp;lt;ul&amp;gt;
            {Belt.Array.map(items, ({fullName, htmlUrl}: GhRepo.repo) =&amp;gt;
               &amp;lt;li key=fullName&amp;gt;
                 &amp;lt;a href=htmlUrl&amp;gt; {ReasonReact.string(fullName)} &amp;lt;/a&amp;gt;
               &amp;lt;/li&amp;gt;
             )
             -&amp;gt;React.array}
          &amp;lt;/ul&amp;gt;
        | Complete(Error(`FetchError(_))) =&amp;gt;
          ReasonReact.string("Fetch error!")
        | Complete(Error(`DecodeError(_))) =&amp;gt;
          ReasonReact.string("Decode error!")
      )
  );
};

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



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

&lt;p&gt;So, all in all, composable error handling with real-world ReasonML libraries is quite possible, with a few caveats.&lt;/p&gt;

&lt;p&gt;Firstly, out of 2 libs we’ve tried, neither used polymorphic variants, so we’ve taken their own (non-discernible) errors and wrapped them in our polymorphic variants. Not very granular, but then the consuming code didn’t have to branch over a whole lot of variants. I imagine having a few dozens possible variants would bring its inconveniences as well.&lt;/p&gt;

&lt;p&gt;Secondly, to make polymorphic variants extensible, you’re going to have to parametrize a few things here and there. But OCaml type inference being seriously impressive, that problem is very manageable; at least, you don’t have to be verbose to solve it.&lt;/p&gt;

&lt;p&gt;Is that all? Maybe that’s all. And oh, &lt;a href="https://github.com/hoichi/rwceh"&gt;here’s the repo&lt;/a&gt; with the code.&lt;/p&gt;




&lt;p&gt;Posted first at &lt;a href="https://hoichi.io"&gt;hoichi.io&lt;/a&gt;, because home sweet home.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Type-And-Test Driven Development</title>
      <dc:creator>Sergey Samokhov</dc:creator>
      <pubDate>Mon, 04 Nov 2019 11:53:00 +0000</pubDate>
      <link>https://dev.to/hoichi/type-and-test-driven-development-5c9g</link>
      <guid>https://dev.to/hoichi/type-and-test-driven-development-5c9g</guid>
      <description>&lt;h2&gt;
  
  
  The Question
&lt;/h2&gt;

&lt;p&gt;I know what type-driven development is (didn’t say I’ve mastered it). I sort of get what is test-driven development, or even &lt;a href="https://www.jamesshore.com/Blog/Red-Green-Refactor.html"&gt;red-green-refactor&lt;/a&gt;. But can you do both at the same time? If you start with types, is there anything left of the green-red-refactor cycle? Or does that mean you write your tests post factum?&lt;/p&gt;

&lt;p&gt;The typed language I use for the experiment is, by the way, ReasonML, which is basically another syntax for OCaml. Not that I think it matters much: I have more experience with TypeScript, but OCaml is seemingly a smaller language and its type system feels slightly simpler. Overall, whether a cognitive load of doing OCaml types is bigger or smaller compared to TS, it’s probably not by much. Or something.&lt;/p&gt;

&lt;p&gt;Spoiler: turns out doing both iteratively is easier than I thought, but it’s not always such an even-going process as the basic TDD examples would make you believe.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Task
&lt;/h2&gt;

&lt;p&gt;Let’s suppose that we need collections of blog posts to use in all kinds of post lists, like a blog feed, tag pages, and RSS. For simplicity’s sake, though, let’s not think about pagination or filtering, and instead create a simple API that allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a collection;&lt;/li&gt;
&lt;li&gt;Adding posts to a collection;

&lt;ul&gt;
&lt;li&gt;adding a post with the same path should update the existing record;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Getting an array of posts;

&lt;ul&gt;
&lt;li&gt;should be a sorted array.&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;And without any further design (some people would make you think that tests are all the design you’ll ever need, and others advise you &lt;em&gt;design with types&lt;/em&gt;), we set off.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Most Minimal Array
&lt;/h2&gt;

&lt;p&gt;A real true honest-to-god TDD aficionado might start with &lt;code&gt;expect([||]) |&amp;gt; toBe([||])&lt;/code&gt;. Coming from static types, that feels like too little code, but hey, maybe that’s a good exercise, so let’s roll with it.&lt;/p&gt;

&lt;p&gt;But let’s actually have some code to test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Collection_test.re
expect(Collection.toArray()) |&amp;gt; toEqual([||]);

// Collection.re
let toArray = () =&amp;gt; [||];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That API is not quite right. Shouldn’t we create a collection first? Shouldn’t &lt;code&gt;toArray&lt;/code&gt; accept &lt;code&gt;Collection.t&lt;/code&gt;? Let’s start by updating the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(Collection.make()-&amp;gt;Collection.toArray) |&amp;gt; toEqual([||]);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That breaks our types. Let’s fix them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let make = () =&amp;gt; ();

let toArray = _ =&amp;gt; [||];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Or, if you feel farsighted,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let make = () =&amp;gt; [||];

let toArray = a =&amp;gt; a;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Again, we try to keep up the red-green spirit and write the least amount of code to pass a test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding values
&lt;/h2&gt;

&lt;p&gt;An empty collection is more or less covered; let’s add values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// collection_test.re
expect(Collection.(make()-&amp;gt;add(1)-&amp;gt;toArray)) |&amp;gt; toEqual([|1|]);

// collection.re
let add = (arr, el) =&amp;gt; Js.Array2.concat(arr, [|el|]);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now two values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(Collection.(make()-&amp;gt;add(1)-&amp;gt;add(2)-&amp;gt;toArray)) |&amp;gt; toEqual([|1, 2|])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Three values!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(Collection.(
  make()-&amp;gt;add(1)-&amp;gt;add(2)-&amp;gt;add(3)-&amp;gt;toArray))
|&amp;gt; toEqual([|1, 2, 3|])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Hey, I could do this all day.&lt;/p&gt;

&lt;h2&gt;
  
  
  And How Is It Type-Driven, Exactly?
&lt;/h2&gt;

&lt;p&gt;We’re interrupting our flow to ask ourselves: isn’t all of the above just the plain old TDD (as in, &lt;em&gt;test&lt;/em&gt;-driven). Weren’t we supposed to start our design like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type t;
let make: unit =&amp;gt; t;
let add: (t, Post.t) =&amp;gt; t;
let toArray: t =&amp;gt; array(Post.t);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Maybe we wouldn’t even end up with those useless &lt;code&gt;int&lt;/code&gt; tests. Because I already smell trouble ahead. But let’s ignore the smell for a minute and see where does this precarious path lead.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Stab at Sorting
&lt;/h2&gt;

&lt;p&gt;Here’s a test for sorting order. Look out below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(Collection.(make()-&amp;gt;add(3)-&amp;gt;add(5)-&amp;gt;add(2)-&amp;gt;add(-4)-&amp;gt;toArray))
|&amp;gt; toEqual([|(-4), 2, 3, 5|])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I just knew it. Broken.&lt;/p&gt;

&lt;p&gt;By the way, that test exemplifies a possible bug that types won’t catch. Not the OCaml/Reason types, at least.&lt;/p&gt;

&lt;p&gt;But let’s implement sorting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types Head Their Rear Again
&lt;/h2&gt;

&lt;p&gt;This is when I’m beginning to have second thoughts about the red-green minimalism. Obviously (to me), the next &lt;em&gt;minimal&lt;/em&gt; step is to sort the &lt;code&gt;int&lt;/code&gt;s to fix the test. But our actual goal isn’t to sort &lt;code&gt;int&lt;/code&gt;s. We need to sort &lt;em&gt;articles&lt;/em&gt;. By &lt;em&gt;dates&lt;/em&gt;. And if we sort &lt;code&gt;int&lt;/code&gt;s now, we’ll have more tests to refactor later.&lt;/p&gt;

&lt;p&gt;Shall we skip to the next step then, and sort dates? The quickest would be to use polymorphic comparison, which feels a little flaky, and anyway, all this thinking got me thinking: do I want to create a collection of &lt;em&gt;anything&lt;/em&gt;, or do I merely need a collection of posts? Because the former would require a functor with a few parameters.&lt;/p&gt;

&lt;p&gt;Of course, functors are cool and make you feel like a real programmer. They also probably make property testing easier, and property tests make you feel safer. But then again, a functor would make you have to write more tests to make sure parametrization works correctly. So, no, can’t be bothered with functors for now. Not until I need to collect something other than posts.&lt;/p&gt;

&lt;p&gt;So, answering the question of what to sort, yes, I could go and change &lt;code&gt;Collection.t&lt;/code&gt; to &lt;code&gt;Js.Date.t&lt;/code&gt; and rewrite the &lt;code&gt;int&lt;/code&gt; tests accordingly. I’d even be able to reuse the dates sorting logic and the date values in the tests. But since I’ve already taken myself out of the busy mood, I say let’s bite the bullet and switch to the actual posts already.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter The Actual Posts
&lt;/h2&gt;

&lt;p&gt;One more thing before we dive back into the red-green rush. We’re probably going to create more mock posts that is healthy to read in full form. Better add some helpers for readability.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// some mocks from our stash
module Any = { module Old = Mock.AnyOld; }

let postWithDate =
  dateStr =&amp;gt; Post.{
    meta: {
      ...Any.Old.meta,
      date: Js.Date.fromString(dateStr),
    },
    title: "",
    content: Markup.Markdown(""),
    excerpt: Markup.Markdown(""),
    source: Any.Old.source,
  };

let postsArray = Belt.Array.map(_, postWithDate);
let addPosts = (c: Collection.t, posts) =&amp;gt;
  postsArray(posts)-&amp;gt;Belt.Array.reduce(c, Collection.add);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And with that, let’s rewrite our singleton collection test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test("single value", () =&amp;gt;
  expect(
    Collection.(make()-&amp;gt;addPosts([|"2019-06-01T20:38:01.155Z"|])-&amp;gt;toArray),
  )
  |&amp;gt; toEqual(postsArray([|"2019-06-01T20:38:01.155Z"|]))
);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Green. All right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sorting, Continued
&lt;/h2&gt;

&lt;p&gt;Feel like breaking something?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test("several unsorted values", () =&amp;gt;
  expect(
    Collection.(
      make()-&amp;gt;addPosts([|"2019-09-01", "2019-07-01", "2019-05-02"|])-&amp;gt;toArray
    ),
  )
  |&amp;gt; toEqual(postsArray([|"2019-05-02", "2019-07-01", "2019-09-01"|]))
);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And we’re in the red again. Time to do the sorting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let toArray =
  Belt.SortArray.stableSortBy(_, (p1: Post.t, p2: Post.t) =&amp;gt;
    Js.Date.(compare(p1.meta.date-&amp;gt;getTime, p2.meta.date-&amp;gt;getTime))
  );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That wasn’t too hard. Of course, it’s not a final implementation, as we’ll see in a minute, but we’re getting close.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating by Path
&lt;/h2&gt;

&lt;p&gt;There’s one part of spec left to implement. If we add a post with the same full path for a second or third or whichever time, our collection should only hold the latest value.&lt;/p&gt;

&lt;p&gt;First, let’s add a parameter to our test helpers to accept different paths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let postWithDate = ((fullPath, dateStr)) =&amp;gt;
  Post.{
    meta: {
      ...Any.Old.meta,
      date: Js.Date.fromString(dateStr),
    },
    title: "",
    content: Markup.Markdown(""),
    excerpt: Markup.Markdown(""),
    source: {
      ...Any.Old.source,
      path: {
        ...Any.Old.source.path,
        full: fullPath,
      },
    },
  };
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Digression: did you notice how I didn’t have to update &lt;code&gt;postArray&lt;/code&gt; and &lt;code&gt;addPosts&lt;/code&gt;? Point-free programming in OCaml is pretty neat, even without the &lt;code&gt;composeRight&lt;/code&gt; operator.&lt;/p&gt;

&lt;p&gt;Anyway, here’s how tests should look now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test("several unsorted values", () =&amp;gt;
  expect(
    Collection.(
      make()
      -&amp;gt;addPosts([|
          ("a/x.md", "2019-09-01"),
          ("a/y.md", "2019-07-01"),
          ("a/z.md", "2019-05-02"),
        |])
      -&amp;gt;toArray
    ),
  )
  |&amp;gt; toEqual(
       postsArray([|
         ("a/z.md", "2019-05-02"),
         ("a/y.md", "2019-07-01"),
         ("a/x.md", "2019-09-01"),
       |]),
     )
);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now let’s try to repeat some paths:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test("same paths get updated", () =&amp;gt;
  expect(
    Collection.(
      make()
      -&amp;gt;addPosts([|
          ("a/x.md", "2019-09-01"),
          ("a/y.md", "2019-07-01"),
          ("a/z.md", "2019-05-02"),
          ("a/y.md", "2019-04-01"),
          ("a/x.md", "2019-01-09"),
        |])
      -&amp;gt;toArray
    ),
  )
  |&amp;gt; toEqual(
       postsArray([|
         ("a/x.md", "2019-01-09"),
         ("a/y.md", "2019-04-01"),
         ("a/z.md", "2019-05-02"),
       |]),
     )
);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Red, as expected. Let’s update the implementation. Our requirements sound like a job for a Map, which means we should update the &lt;code&gt;t&lt;/code&gt; implementation and pretty much all the functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;open Belt;

module PostCmp =
  Id.MakeComparable({
    type t = string;
    let cmp = Pervasives.compare;
  });

type t = Map.t(string, Post.t, PostCmp.identity);

let make = () =&amp;gt; Map.make(~id=(module PostCmp));

let add = (m, p: Post.t) =&amp;gt; Belt.Map.set(m, p.source.path.full, p);

let toArray = m =&amp;gt;
  Map.valuesToArray(m)
  -&amp;gt;SortArray.stableSortBy(_, (p1: Post.t, p2: Post.t) =&amp;gt;
      Js.Date.(compare(p1.meta.date-&amp;gt;getTime, p2.meta.date-&amp;gt;getTime))
    );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And with that, we’re green once again and more or less done.&lt;/p&gt;

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

&lt;p&gt;In the beginning, we’ve asked ourselves if it’s possible to combine type-driven development and red-green-refactor-flavored &lt;em&gt;test&lt;/em&gt;-driven development. And the short answer is that it is indeed possible to do both at once and do it iteratively.&lt;/p&gt;

&lt;p&gt;Of course, the above is just one data point, and neither the types nor the implementation was too complicated. Still, in this particular example, it seems the combined complexity of types and test cases is very manageable.&lt;/p&gt;

&lt;p&gt;Here are a few finer points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Even with types, you still need some unit tests. E.g., you can’t encode sorting order in types (at least not in ML).&lt;/li&gt;
&lt;li&gt;It’s nice to be able to keep your red-green cycles short, but sometimes it makes more sense to slow down. That breaks your stride, yes, but I think the ability to stop and think when called for is as crucial for a programmer as the ability to pivot for an agile team.&lt;/li&gt;
&lt;li&gt;It pays to have a written spec, however brief, before you start coding. Were we to start writing my “specs” in tests, or even in types, it might have taken noticeably more cycles.&lt;/li&gt;
&lt;li&gt;And by the way, with the helpers we wrote, it should be relatively easy to write property tests.&lt;/li&gt;
&lt;li&gt;But that is a story for another day.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Posted first at &lt;a href="https://hoichi.io"&gt;hoichi.io&lt;/a&gt;, but you’re welcome to read it anywhere.&lt;/p&gt;

</description>
      <category>reason</category>
      <category>types</category>
      <category>tdd</category>
    </item>
    <item>
      <title>How Not to Introduce ReasonReact to Your Project</title>
      <dc:creator>Sergey Samokhov</dc:creator>
      <pubDate>Sat, 19 Jan 2019 11:53:00 +0000</pubDate>
      <link>https://dev.to/hoichi/how-not-to-introduce-reasonreact-to-your-project-311o</link>
      <guid>https://dev.to/hoichi/how-not-to-introduce-reasonreact-to-your-project-311o</guid>
      <description>&lt;p&gt;Well, &lt;em&gt;actually&lt;/em&gt; the reality is not as harsh as the clickbaitey title would make you think. Nothing particularly wrong came out of my introduction of ReasonReact and, by extension, ReasonML to the static build of this very site. The claim that you can introduce Reason &amp;amp; ReasonReact to an existing application one component at a time is entirely true.&lt;/p&gt;

&lt;p&gt;Moreover, ReasonML is pretty sweet, and BuckleScript is the bestest, fastest, most optimizing -to-JS compiler I know of.&lt;/p&gt;

&lt;p&gt;It’s just that my particular implementation was just a little bit inefficient and probably not a good management decision. If I could go back in time, I’d do it differently—or maybe wouldn’t do at all in the foreseeable future.&lt;/p&gt;

&lt;p&gt;That disclaimer aside, let me start from the start.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Wrong With TypeScript
&lt;/h2&gt;

&lt;p&gt;The reason I was eyeing a language like ReasonML is that TypeScript seems a tad suboptimal for me (and a little boring). It’s still wordy, all the ESNext advances notwithstanding. You can emulate both sum types and exhaustive cases in it, but they look somewhat monstrous. Its types give you way fewer guarantees than, say, types in ML languages. And don’t get me started on FP patterns in JS: &lt;code&gt;pipe(foo, bar, baz)(x)&lt;/code&gt; reads infinitely less natural than &lt;code&gt;x |&amp;gt; foo |&amp;gt; bar |&amp;gt; baz&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Probably as important as the guarantees, it feels like the TypeScript types allow you a little too much. Extending object types, for one. Yes, &lt;code&gt;Object.assign()&lt;/code&gt; is totally a thing in JavaScript that those types are modeling. Yes, often it does feel convenient to go and add some more properties to an existing object.&lt;/p&gt;

&lt;p&gt;It also leads to lazy thinking. Take my static site build scripts. They have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pages (posts) as I read them off a file system, with path information and raw content data&lt;/li&gt;
&lt;li&gt;Same, with YAML frontmatter extracted and markdown parsed to HTML&lt;/li&gt;
&lt;li&gt;Same, put into lists for blog feed, tag feeds, and RSS&lt;/li&gt;
&lt;li&gt;Both individual pages and feed pages, wrapped in the appropriate page/post layout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The types for all of the above are way under-designed because every single time I thought: Nah, I’ll just copy the old object with some extra prop, and maybe override the &lt;code&gt;content&lt;/code&gt; property, nevermind it’s now HTML instead of Markdown. Yes, I know that with proper discipline you can sit down and think those specs through, but discipline is depletable, so you tend to wing it—and then waste time setting breakpoints and logging stuff.&lt;/p&gt;

&lt;p&gt;So I hoped that OCaml’s restrictive records would nudge me towards designing with types.&lt;/p&gt;

&lt;p&gt;There was also some nice-to-haves, like maybe processing more data with the Reason standard library in a more concise way, or maybe turning my blog into semi-SPA with ReasonReact. Not that the page load speed is a problem I have with a Netlify-hosted static site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why, Then, Have I Started With Templating
&lt;/h2&gt;

&lt;p&gt;But all of a sudden I’ve decided that I need to introduce comments. &lt;em&gt;And&lt;/em&gt; maybe a new theme. &lt;em&gt;And&lt;/em&gt; all of it to improve the chances of getting a better job. For that, one felt, the lack of ReasonReact was a showstopper. For if I were to use it later at all, doing work on my current Jade templates felt a little wasteful.&lt;/p&gt;

&lt;p&gt;So, instead of solving an interesting problem of designing with types, I’ve found myself doing something closer to a chore. Also, was I sure it was necessary? Do I have actual plans to evolve the client part of my blog? All for fear of not finding a good job? Is blogging on random tech bits something I want more than just hacking or learning stuff?&lt;/p&gt;

&lt;p&gt;Lousy management, like I said. False urgency over importance.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, How It Went?
&lt;/h2&gt;

&lt;p&gt;Well, it went ok. I had to resort to a little hack because the BuckleScript compiler has fewer options regarding input/output dirs. I also had to use the &lt;code&gt;rss&lt;/code&gt; package, because React’s idea of how you use the &lt;code&gt;link&lt;/code&gt; tag is not compatible with how it is used in RSS (which is not HTML, of course, but try telling it to React). But then maybe my feed is now more standard-compliant for it, and converting some random Atom example to Jade was a worse hack, to begin with.&lt;/p&gt;

&lt;p&gt;However, the whole result is also mildly useless. The scheme is now like this: I’ve got a &lt;code&gt;templates.re&lt;/code&gt; file that returns a dictionary of template functions to be consumed in JS-land. So, it uses JS interop to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;construct the dictionary itself&lt;/li&gt;
&lt;li&gt;wrap the individual templates and convert the JS param objects to ML labeled parameters&lt;/li&gt;
&lt;li&gt;also, for templates that get arrays of posts and tags, get individual props off those posts and tags, because I’ve got too lazy to convert those objects to proper ML records&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, the bulk of my work went into the interop that I’m going to have to throw away when (or if) I convert everything to Reason/OCaml. Mind you, BuckleScript JS interop is pretty terrific, and ReasonML sugar for it is great too, But the process is just a bit tedious and doesn’t feel like making something important, especially since it’s all makeshift.&lt;/p&gt;

&lt;p&gt;Conversely, there isn’t a whole lot of ML to ML API: the wrappers pass ML params to the templates, and those pass them on to the ReasonReact components. Not that many types to help me grok my state management, or yell at me if I do something wrong.&lt;/p&gt;

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

&lt;p&gt;All in all, I did add a few smallish ReasonReact components to a TypeScript module, and they work. As far as learning projects go, it went well. What I’ve learned wasn’t particularly fundamental, but then you can’t do much practical stuff without some non-fundamental knowledge. The bane of project-based learning, I guess.&lt;/p&gt;

&lt;p&gt;Next time, though, I’m going to think twice whether it’s worth it, and where that new technology is going to have the most impact. Using Reason or OCaml for the build logic itself would take longer, but might bring more clarity. Converting everything would take even longer, but would free me from having to write that interop code—or rather, I’d have to write it for some other modules, like &lt;a href="https://mostcore.readthedocs.io/en/latest/"&gt;@most/core&lt;/a&gt;.Provided I’d managed to debug the whole thing at once.&lt;/p&gt;

&lt;p&gt;Especially since I have minimal experience with tests. Maybe I should write more of those in 2019.&lt;/p&gt;




&lt;p&gt;Posted first at &lt;a href="https://hoichi.io"&gt;hoichi.io&lt;/a&gt;, but you’re welcome to read it anywhere.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Tail-optimized functions in ReasonML</title>
      <dc:creator>Sergey Samokhov</dc:creator>
      <pubDate>Sat, 15 Sep 2018 11:30:00 +0000</pubDate>
      <link>https://dev.to/hoichi/tail-optimized-functions-in-reasonml-48eo</link>
      <guid>https://dev.to/hoichi/tail-optimized-functions-in-reasonml-48eo</guid>
      <description>&lt;p&gt;All the examples are in &lt;a href="https://reasonml.github.io"&gt;ReasonML&lt;/a&gt;, which, very roughly speaking, is a cross of OCaml &amp;amp; JS I’m very interested in at the moment.&lt;/p&gt;

&lt;p&gt;With that intro aside, let’s write a function that generates a range of ints, i.e., takes a tuple of &lt;code&gt;(beginning, end)&lt;/code&gt; and returns a list of all &lt;code&gt;int&lt;/code&gt;s in between, including the boundaries. The naive approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let rec genRange = ((min, max)) =&amp;gt;
  min &amp;gt; max
    ? []
    : [min, ...genRange((min + 1, max))];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The problem with it is if the range is rather long, it may cause a stack overflow. See this expression: &lt;code&gt;[min, ...genRange((min + 1, max))]&lt;/code&gt;? To evaluate it the machine has to wait for the recursive call to return and then use the return value to build the longer list.&lt;/p&gt;

&lt;p&gt;(Would be even worse with arrays, by the way. You’d have as many arrays as there would be elements in a final result, and they wouldn’t share any of the memory between them, effectively allocating about &lt;code&gt;(len+1) * len/2&lt;/code&gt; elements, none of which could be garbage collected or otherwise freed until the most deeply nested calls start to return.)&lt;/p&gt;

&lt;p&gt;Now, both the native OCaml compiler and BuckleScript (the latter compiles OCaml/ReasonML to JS) support tail call optimization. Meaning that instead of adding another frame to the stack, the compiler makes the generated code to reuse the current one. (It’s a bit different in JS code, but we’ll get to it later.)&lt;/p&gt;

&lt;p&gt;For that mechanism to work, you have to be sure you don’t do anything with the result of the recursive call other than return it as is. That way, you don’t have to return at all. The function instance that is called last evaluates the final result and returns it straight to the original callee.&lt;/p&gt;

&lt;p&gt;However, that means that the instance you call last should have all the data to evaluate that final value. Passed as parameters (since we’re talking FP). So, our old naive &lt;code&gt;gen_range&lt;/code&gt; doesn’t cut it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gen_range&lt;/code&gt; already has &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; as its parameters. What does it lack from that expression, &lt;code&gt;[min, ...gen_range((min + 1, max))]&lt;/code&gt;, to evaluate full list on the final step?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;min&lt;/code&gt;? We already have it. The result of &lt;code&gt;gen_range(min + 1, max)&lt;/code&gt;? That’s more like it. We need to pass the current version of the list to build the next one. Let’s add &lt;code&gt;list&lt;/code&gt; as a parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let rec genRangeTco = (list, (min, max)) =&amp;gt;
  max &amp;lt; min
    ? list
    : genRangeTco([max, ...list], (min, max - 1));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You might have noticed that now we do not increase &lt;code&gt;min&lt;/code&gt;, we decrease &lt;code&gt;max&lt;/code&gt; instead. Looks a bit unnatural, especially if your ‘natural’ is the good old &lt;code&gt;i++&lt;/code&gt;, but it’s closer to how lists are built: what was the head yesterday, today is part of the tail.&lt;/p&gt;

&lt;p&gt;Another quite noticeable thing is that the signature is less convenient now: you have to provide an empty list as a parameter. This is why with TCO functions, the recursive one is usually a helper function, and users get a dumbed down version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let genRangeTco = {
  let rec helper = (list, (min, max)) =&amp;gt;
    max &amp;lt; min
      ? list
      : helper([max, ...list], (min, max - 1));

  helper([]);
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;helper([])&lt;/code&gt; is a partial application, by the way, pre-applying an empty list to &lt;code&gt;helper&lt;/code&gt; and returning a function that expects a tuple of &lt;code&gt;(min, max)&lt;/code&gt;, just like our first version.&lt;/p&gt;

&lt;p&gt;One last thing. The future of tail call optimization proposal is, as I’m writing this, &lt;a href="https://www.reddit.com/r/node/comments/8qfhy0/what_happened_to_tco_tail_call_optimization_after/"&gt;quite murky&lt;/a&gt;. But the BuckleScript compiler (that, again, kind of powers ReasonML), hellbent as it is on performance of the JS it generates, won’t be denied. See what it does with the naive version first: &lt;a href="https://reasonml.github.io/en/try?rrjsx=true&amp;amp;reason=DYUwLgBATiDGEHMQDsBKBDZSIF4IAp8BbAS2QBoIj0APASjtwD4AoCKsiJq2t9iAPwQA2gF0+7AFwjSFCADpFSNJiSFZEANQQAjJWr06ogNwsgA"&gt;the good ole recursive call&lt;/a&gt;, nothing special, amirite? And now, behold, &lt;a href="https://reasonml.github.io/en/try?rrjsx=true&amp;amp;reason=DYUwLgBA5iB2BKBDWMAqBjA9hAvBA3gFAQSiQBOI6EAFiMAA4jm4QAUwAlgM5gA07ALadYAwYgAeASim4AfMRIRxEiAB5lIxUogB+UjzDalALlr0m5NgG0VAgHSOuvALoC2w0cskQAtBABGGQBuQkU6RmYbFylQgF9QoA"&gt;the tail-optimized version&lt;/a&gt;. It’s got compiled to a loop!&lt;/p&gt;

&lt;p&gt;See why I’m interested in Reason?&lt;/p&gt;




&lt;p&gt;Posted first at &lt;a href="https://hoichi.io"&gt;hoichi.io&lt;/a&gt;, because home sweet home.&lt;/p&gt;

</description>
      <category>reason</category>
      <category>recursion</category>
    </item>
    <item>
      <title>TIL: Why ReasonML Has No Nullary Functions</title>
      <dc:creator>Sergey Samokhov</dc:creator>
      <pubDate>Fri, 17 Aug 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/hoichi/til-why-reasonml-has-no-nullary-functions-5e03</link>
      <guid>https://dev.to/hoichi/til-why-reasonml-has-no-nullary-functions-5e03</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Why doesn’t ReasonML have nullary functions? That is due to ReasonML always performing partial application (explained in detail later): If you don’t provide all of a function’s parameters, you get a new function from the remaining parameters to the result. As a consequence, if you could actually provide no parameters at all, then func() would be the same as func and neither would actually call func.&lt;br&gt;&lt;br&gt;
– &lt;a href="http://reasonmlhub.com/exploring-reasonml/ch_functions.html#there-are-no-functions-without-parameters"&gt;Exploring ReasonML and functional programming&lt;/a&gt; by Dr. Axel Rauschmayer&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Posted first at &lt;a href="https://hoichi.io"&gt;hoichi.io&lt;/a&gt;, because you can’t be too paranoid.&lt;/p&gt;

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