<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Antti Pitkänen</title>
    <description>The latest articles on Forem by Antti Pitkänen (@anttispitkanen).</description>
    <link>https://forem.com/anttispitkanen</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%2F767441%2Fa72b9fde-dbca-4667-9fc6-24cf9d39c48a.jpeg</url>
      <title>Forem: Antti Pitkänen</title>
      <link>https://forem.com/anttispitkanen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/anttispitkanen"/>
    <language>en</language>
    <item>
      <title>TypeScript: why you shouldn't throw errors to control the program flow</title>
      <dc:creator>Antti Pitkänen</dc:creator>
      <pubDate>Mon, 10 Apr 2023 14:05:53 +0000</pubDate>
      <link>https://forem.com/anttispitkanen/typescript-why-you-shouldnt-throw-errors-to-control-the-program-flow-3g91</link>
      <guid>https://forem.com/anttispitkanen/typescript-why-you-shouldnt-throw-errors-to-control-the-program-flow-3g91</guid>
      <description>&lt;p&gt;The title is a hot take, and as any experienced software engineer can attest, "it depends". But here I'll explain what kinds of problems stem from using error throwing as a means to control the program flow, why that is, and what can be done instead.&lt;/p&gt;

&lt;p&gt;In a nutshell:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Errors and the &lt;code&gt;try/catch&lt;/code&gt; mechanism are good for safeguarding against bugs and other unexpected behaviour, and recovering from them.&lt;/li&gt;
&lt;li&gt;Errors and &lt;code&gt;try/catch&lt;/code&gt; are suboptimal for representing and handling expected failure states in code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Error&lt;/code&gt;s in action
&lt;/h2&gt;

&lt;p&gt;What's wrong with code like this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** A crude emulation of a database of user IDs */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userDatabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User not found with id: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="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;You could say there's nothing wrong. After all you can call it downstream perfectly fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doSomethingWithUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what happens if you pass in an ID that's not found in our makeshift user database? The &lt;code&gt;getUser&lt;/code&gt; function will &lt;code&gt;throw&lt;/code&gt; and error, which the &lt;code&gt;doSomethingWithUser&lt;/code&gt; function doesn't handle. Instead it will bubble up to wherever &lt;code&gt;doSomethingWithUser&lt;/code&gt; is invoked from.&lt;/p&gt;

&lt;p&gt;This example may look trivial enough to solve, as you can just employ a &lt;code&gt;try/catch&lt;/code&gt; block in the caller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doSomethingWithUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do something with the error&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;Now, in the &lt;code&gt;catch&lt;/code&gt; block, you can prevent the error from bubbling up further, and instead handle the situation in a meaningful way. Maybe you want to return some sensible default, maybe &lt;code&gt;undefined&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;, maybe log an error message - anything is an option. &lt;/p&gt;

&lt;p&gt;So is there a problem?&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: Errors are not part of the type signature
&lt;/h2&gt;

&lt;p&gt;If we look at the inferred type signature of &lt;code&gt;getUser&lt;/code&gt;, we see that it's &lt;code&gt;(id: string) =&amp;gt; number&lt;/code&gt;. In other words, the compiler is telling us that this function will return a value that is of type &lt;code&gt;number&lt;/code&gt;. This is also how we would type the function manually.&lt;/p&gt;

&lt;p&gt;There's no indication of the fact that the function can throw an error, let alone what kind of error the function can throw. In order to get to know that, it needs to be separately documented, or the function source code needs to be examined to determine its behaviour. This is against the principle of &lt;a href="https://en.wikipedia.org/wiki/Information_hiding"&gt;information hiding&lt;/a&gt;, as the interface itself is not explaining how the function can be used.&lt;/p&gt;

&lt;p&gt;TypeScript's type system has no way to encode the functions that can be thrown from a piece of code into a meaningful type representation, &lt;a href="https://github.com/microsoft/TypeScript/issues/23689"&gt;at least as of now&lt;/a&gt;. This means that the compiler cannot indicate that the programmer should prepare for an error being thrown and handle it accordingly. &lt;/p&gt;

&lt;p&gt;When you write a &lt;code&gt;catch (err) {}&lt;/code&gt; block, the type of &lt;code&gt;err&lt;/code&gt; is always &lt;code&gt;unknown&lt;/code&gt;. This is a result of the above, but also the fact that in TypeScript and the underlying JavaScript, errors are thrown when bugs happen. Your function might throw an error that's explicitly thrown in the code, but it might also have a bug in it and throw an unexpected &lt;code&gt;TypeError: undefined is not a function&lt;/code&gt; or something similar. We'll discuss error boundaries as a solution to this below.&lt;/p&gt;

&lt;p&gt;The problem might not seem that bad in our silly little example, but in reality there might be a deep call stack between the function where the error is thrown, and the invoking piece of code that should be able to handle the error gracefully. For example, if you install an external library that provides the &lt;code&gt;getUser&lt;/code&gt; function, you might not have similar visibility into the library internals. And even if you do, ideally the type system would give you a good enough API schema description to work with, hiding the information about the detail level implementation. &lt;/p&gt;

&lt;p&gt;The problem is the more significant the larger the code base and the team working on it is. You might look at the type signature of a function written by someone else and imagine it fits your use case, without knowing anything about a crucial part of its behaviour.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do instead?
&lt;/h2&gt;

&lt;p&gt;We can solve the information hiding problem with &lt;strong&gt;discriminated unions&lt;/strong&gt;. But in order to make this logic sound, we need to apply sensible &lt;strong&gt;error boundaries&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Discriminated unions for better compiler support
&lt;/h3&gt;

&lt;p&gt;To make the compiler more aware of the expected failure cases and help the programmer handle those, we can return the failures from the functions instead of throwing them. Now, the function can return &lt;em&gt;either&lt;/em&gt; a success or a failure, both with relevant data. See &lt;a href="https://dev.to/anttispitkanen/using-discriminated-union-types-in-typescript-2co6"&gt;my earlier post about about discriminated unions&lt;/a&gt; for more information on the subject, but in practice it could look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetUserFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetUserSuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetUserResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GetUserFailure&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GetUserSuccess&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;getUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;GetUserResult&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No error is thrown, and instead we return a type that is either a success or a failure. Then we can use the discriminator property, in this case the &lt;code&gt;_t&lt;/code&gt;, to identify which result we got. Now we can work with any traditional conditional mechanisms: &lt;code&gt;if/else&lt;/code&gt; statements, ternary operators, or a &lt;code&gt;switch&lt;/code&gt; statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doSomethingWithUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// There was no user, so result is a failure,&lt;/span&gt;
      &lt;span class="c1"&gt;// handle the situation somehow&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// There was a user, so result is a success,&lt;/span&gt;
      &lt;span class="c1"&gt;// and we have an ID&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&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="k"&gt;break&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;Just by inspecting the function's type signature, &lt;code&gt;(id: number) =&amp;gt; GetUserResult&lt;/code&gt;, we know that there are two possible outcomes of invoking the function, both of which we should handle in the invoking code. &lt;/p&gt;

&lt;p&gt;And that's not all, because we don't have to limit ourselves to two options. In the real world our user database is probably not a hardcoded array, but some external data store we need to call. We can easily express that as its own scenario, something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ConnectionFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;connection-failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetUserFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-not-found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetUserSuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetUserResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ConnectionFailure&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GetUserFailure&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GetUserSuccess&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;getUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;GetUserResult&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;// Connect to the database, fail on 10% of the calls&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;connection-failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-not-found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can call the function and handle the different outcomes with just one more branch of logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doSomethingWithUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;connection-failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// There was a connection failure,&lt;/span&gt;
      &lt;span class="c1"&gt;// handle the situation somehow&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-not-found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// There was no user, so result is a failure,&lt;/span&gt;
      &lt;span class="c1"&gt;// handle the situation somehow&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// There was a user, so result is a success,&lt;/span&gt;
      &lt;span class="c1"&gt;// and we have an ID&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&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="k"&gt;break&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;Note that here we have now three different "top level outcomes" in the return type union. Alternatively we could group everything under either a success or a failure, and have different subtypes of failures.&lt;/p&gt;

&lt;h4&gt;
  
  
  Quick aside: the Either monad
&lt;/h4&gt;

&lt;p&gt;Those familiar with more functional languages might be screaming about monads at their screens now. Indeed, if we want to go a step further than using discriminated unions, we can apply &lt;a href="https://gcanti.github.io/fp-ts/modules/Either.ts.html"&gt;Either monads&lt;/a&gt;. Those come with a whole lot of useful tooling with them, like the possibility of monadic pattern matching and chaining operations. We have good experiences of using &lt;a href="https://gcanti.github.io/fp-ts/"&gt;&lt;code&gt;fp-ts&lt;/code&gt;&lt;/a&gt; in my team at Swappie, and even thought the initial learning curve can be steep, the benefits are useful. You can read more about monads in various blog posts all over the web, &lt;a href="https://dev.to/gcanti/getting-started-with-fp-ts-either-vs-validation-5eja"&gt;this one being a good example of &lt;code&gt;Either&lt;/code&gt; specifically&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error boundaries to handle the unexpected errors
&lt;/h3&gt;

&lt;p&gt;Encoding the expected error types in the function return type signature seems useful, but what about the unexpected errors? After all, if we need to handle the expected failures as part of the return type, and still need to &lt;code&gt;try/catch&lt;/code&gt; for unexpected failures anyway, are we any better off?&lt;/p&gt;

&lt;p&gt;Yes and no. No in the sense that due to the dynamic nature of the underlying JavaScript, and the ability to drop in a harmless looking &lt;code&gt;as any&lt;/code&gt; anywhere in the well intentioned TypeScript code, we might be looking at an unexpected runtime error anywhere in the code. But yes in the sense that with some smart architectural decisions we can avoid leaking this problem all over the place, and apply &lt;strong&gt;error boundaries&lt;/strong&gt; where it makes sense.&lt;/p&gt;

&lt;p&gt;An error boundary is in essence a layer in your software architecture where you catch any errors that may have occurred higher up in the call stack, and prevent those from bubbling further. In practice, for our purpose, it would mean having a &lt;code&gt;try/catch&lt;/code&gt; in place, and having the &lt;code&gt;catch&lt;/code&gt; block handle the potential errors. This could mean returning a known failure type instead, logging an error message, or simply doing nothing, depending on the use case.&lt;/p&gt;

&lt;p&gt;In our example, we could turn &lt;code&gt;getUser&lt;/code&gt; into an error boundary by mapping any unknown errors as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ConnectionFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;connection-failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetUserFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-not-found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UnknownFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unknown-failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;err&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetUserSuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetUserResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ConnectionFailure&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GetUserFailure&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;UnknownFailure&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GetUserSuccess&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;getUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;GetUserResult&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Connect to the database, fail on 10% of the calls&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;connection-failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-not-found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unknown-failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="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;Now the whole thing is wrapped in a &lt;code&gt;try/catch&lt;/code&gt;, meaning that even unexpected errors are taken care of in the &lt;code&gt;catch&lt;/code&gt; block. In our tiny example this might seem excessive, as the code is so limited. But let's say that upstream someone had said something silly like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userDatabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="k"&gt;as&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;Now our well intentioned code has a bug:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; Uncaught TypeError: userDatabase.includes is not a function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without the &lt;code&gt;try/catch&lt;/code&gt; this would have bubbled to the caller of our function. Now, the function acts as the error boundary, and we can trust that it won't bubble up errors. The example is obviously a small and trivial one, and in more realistic situations you can imagine there being room for more subtle bugs.&lt;/p&gt;

&lt;p&gt;You don't need to apply error boundaries on every level, that would cause the code to be full of boilerplate. A following blog post will discuss in more detail where error boundaries can be placed in the application architecture. A good guideline is that you would like your business logic to be able to trust any incoming data from upstream, and that instructs where to have an error boundary. &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Using discriminated union types in TypeScript</title>
      <dc:creator>Antti Pitkänen</dc:creator>
      <pubDate>Sun, 19 Mar 2023 13:13:52 +0000</pubDate>
      <link>https://forem.com/anttispitkanen/using-discriminated-union-types-in-typescript-2co6</link>
      <guid>https://forem.com/anttispitkanen/using-discriminated-union-types-in-typescript-2co6</guid>
      <description>&lt;h2&gt;
  
  
  The compile time vs runtime type dilemma
&lt;/h2&gt;

&lt;p&gt;TypeScript is a typed language that compiles to JavaScript, which itself doesn't have types beyond &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof#description" rel="noopener noreferrer"&gt;the primitives&lt;/a&gt;. So when a developer writes TypeScript, it then gets transpiled into JavaScript, which is then executed in the runtime (e.g. a browser, or Nodejs on the server side). The process of transpilation leverages the static type information to catch a whole category of potential bugs, but the resulting runtime code is still just typeless JavaScript.&lt;/p&gt;

&lt;p&gt;This has some implications that surprise developers coming to TypeScript from runtime typed languages. For one, you cannot check the type of anything at runtime, beyond the primitives. In practice:&lt;/p&gt;

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

&lt;span class="c1"&gt;// primitives work...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;myNumber&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; "number"&lt;/span&gt;
&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;myString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; "string"&lt;/span&gt;

&lt;span class="c1"&gt;// ...but more sophisticated types don't&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MyType&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="nl"&gt;func&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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;const&lt;/span&gt; &lt;span class="nx"&gt;myValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyType&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some name for my type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;func&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;myValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; "object", nothing more specific than that&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://www.typescriptlang.org/play?#code/PTAEAcCcEsFtoC7QG4FMDOoDuB7SBrAOmICgBjHAO3QVFgE8A5AV1gCNVJQBeUARgDc5KjTr0AyghiUA5j1ABydDlipQNaTIVCSCeuFQ4AZmJbtOA0CFABaAHygARJVYdIj3fsMmGkzZet7Jw1oWQ8Sa2JCNmZaWDw1ZXAAC2gaaDIAQwRUABNQPQNMXKoFBE8DUABZegAVL3kAbxJQUEpM1QAudSlQmSFWo2ZKMm6ACgBKHgcXc0ghAF8SYWo4+gA1TIAbZlRumvrK3mbW9q7FZVU2jrUjPDECrwUAGhbQIZHxqe4HPgAmADMJCWFW8Yk2O1QATAQUcODYACtUGQEI5nm0cAhUrI6Al1AYyNAjBkCslMpRSdkgA" rel="noopener noreferrer"&gt;The same code in TypeScript playground&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;So let's say we have two types, &lt;code&gt;Cat&lt;/code&gt; and &lt;code&gt;Dog&lt;/code&gt;, and an &lt;code&gt;Animal&lt;/code&gt; type that's a union of both:&lt;/p&gt;

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

&lt;span class="c1"&gt;// all animals in our case share some base attributes&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BaseAnimal&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="nl"&gt;isFluffy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// cats meow&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BaseAnimal&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// dogs bark&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BaseAnimal&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Dog&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;whiskers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cat&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Whiskers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;isFluffy&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="na"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MEOWWW!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Whiskers meows loudly&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;pupper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;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;Pupper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;isFluffy&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;bark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;awooo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Pupper has a gentle awoo instead of a loud bark&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;whiskers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; "MEOWWW!"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pupper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; "awooo"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now let's write some business logic for an &lt;code&gt;Animal&lt;/code&gt; to make noise, regardless of whether it's a &lt;code&gt;Cat&lt;/code&gt; or a &lt;code&gt;Dog&lt;/code&gt;:&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeNoise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ???&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;TypeScript cannot really help you here, as seen in the screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuhh0s9pawov80zqwyfqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuhh0s9pawov80zqwyfqr.png" alt="TypeScript not being able to work on the meow and bark methods"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because of the compile time vs runtime behaviour of types, you cannot do something like this:&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeNoise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Doesn't work because the type doesn't exist at runtime,&lt;/span&gt;
  &lt;span class="c1"&gt;// typeof will just return 'object'&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Instead you can do something like this, but TypeScript is not happy about it:&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeNoise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bark&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meow&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not implemented!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;makeNoise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;whiskers&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; "MEOWWW!"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;makeNoise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pupper&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; "awooo"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;TypeScript's unhappiness comes from the fact that the &lt;code&gt;.meow()&lt;/code&gt; and &lt;code&gt;.bark()&lt;/code&gt; methods don't exist on all the variations of &lt;code&gt;Animal&lt;/code&gt;. Here's what the errors look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ni9sx1twskrcxerb0i1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ni9sx1twskrcxerb0i1.png" alt="TypeScript unable to work with partially accurate information"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even if you accepted this approach, what would happen if the complexity grows? Let's say we want to add a &lt;code&gt;Cat.purr()&lt;/code&gt; and &lt;code&gt;Dog.growl()&lt;/code&gt; method for the types, and add those to the &lt;code&gt;makeNoise&lt;/code&gt; output too. The code would get harder to work with right away, with more complex &lt;code&gt;if&lt;/code&gt; statements and more room for bugs to creep in.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://www.typescriptlang.org/play?#code/PTAEEMBtIg7BLAtlAzqetQHsCuAnUAY3BQFNQUALcPclLRcgIxPPABd294md3SUAKHYBPAA7kAQqwCCCZDAC8oAN6DQoWOEYAuClwwBzANzr0KAGKQcAMxsi9TLFkilwsUwF9BgkEQ5ojFgA7sLi5ADCHKDK0mRySFCgAGSqZkHBegAUAJQxAHz63LAmgt6+YAAmWIZoLHgA1mESoAAiNTGgcaQJCilpGvUN2XmKhSgGJV4+oi29ScpR7KAAPm01PoRYsBOgwZTwKA2keCh6S51qGhpauqAA5ADqB0cnKPcANGYah1a29nouDhSF9rqAMiMCg8ALIAUQA8o8kQBCe6gPzPQ7HU7g0ghNCQXCVSAiMqbba7MQ4MQSPB6dqGS7fTTaUh6e4ABWptM+zN+1jsDlANlQIOZQ0hYwe4GCziwaL8XJpJ1A1DQ4FAhlIsHYrggsqw6B2-HAlWwNggoEJODNQzJgi2OxcpAAdITDFl9li3i6Mrk8n4ALSFABEcMRKJDDopzrdNSyVOVeBdQ396LAwdAIZlcqj5ON4PAxwAclhDuRlFl3IlIHp5pAcnoJsVGVKrtd4BasrM8RbqwoUzQGjFFMp7jYcLBCOx4Nt7nl22CNLR2PhMP2oIPGrlmeUwZ3QN3wlg+-JNxkR2OJ1OZ3OF8ywSu13Aa768cEd2C99cn3hMPdYCwZYkDEVxGB1UhKlRe1HXoVw4w9ZASzLMhPRebEUByAMM1DcMkUeZEo1g2N3SyJDSFLcsE25E4sPTUBM2zA0sCjIA" rel="noopener noreferrer"&gt;The code so far can be played with in TypeScript playground&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution – discriminated unions
&lt;/h2&gt;

&lt;p&gt;The solution for making the runtime "aware" of our compile time types is surprisingly simple. All we need is a &lt;em&gt;tag&lt;/em&gt; for the types to be able to uniquely identify each variant, and &lt;em&gt;discriminate&lt;/em&gt; based on that information. In practice this means adding a property with a literal value that can be used to identify each variant both at compile time and at runtime. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note about the naming.&lt;/strong&gt; The attribute can be called anything as long as the name is consistent between the variants. Here we use &lt;code&gt;_t&lt;/code&gt;. Other commonly used names are &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;tag&lt;/code&gt;, or &lt;code&gt;kind&lt;/code&gt;, with or without an underscore. It could also be something more relevant to the domain that's being modelled, so in our case of animals we could use something like &lt;code&gt;species&lt;/code&gt;.&lt;/p&gt;

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

&lt;span class="c1"&gt;// cats meow&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BaseAnimal&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- the discriminator for cat&lt;/span&gt;
  &lt;span class="na"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// dogs bark&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BaseAnimal&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- the discriminator for dog&lt;/span&gt;
  &lt;span class="na"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Note that the value of &lt;code&gt;_t&lt;/code&gt; needs to be unique for TypeScript to be able to uniquely identify each variant. Now the business logic becomes easier: all we need to do is check for the value of &lt;code&gt;_t&lt;/code&gt;, and the TypeScript compiler knows to automatically &lt;em&gt;narrow&lt;/em&gt; the type based on it. For example, and &lt;code&gt;Animal&lt;/code&gt; with &lt;code&gt;_t === 'dog'&lt;/code&gt; can be narrowed from &lt;code&gt;Animal&lt;/code&gt; to &lt;code&gt;Dog&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note also the &lt;code&gt;assertNever&lt;/code&gt; helper. Here it's used to make sure that all the different variants are handled in the branches of the &lt;code&gt;switch&lt;/code&gt; statement.&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assertNever&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;never&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Should never happen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeNoise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;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;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cat&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;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dog&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;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;assertNever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The following screenshot illustrates how the compiler is able to narrow down from the generic &lt;code&gt;Animal&lt;/code&gt; to the specific &lt;code&gt;Cat&lt;/code&gt; and &lt;code&gt;Dog&lt;/code&gt; based on the code branch we're in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9w6krrbuw7z7nkdr6bc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9w6krrbuw7z7nkdr6bc6.png" alt="The compiler can narrow down the type based on the code branch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://www.typescriptlang.org/play?#code/PTAEEMBtIg7BLAtlAzqetQHsCuAnUAY3BQFNQUALcPclLRcgIxPPABd294md3SUAKHYBPAA7kAQqwCCCZDAC8oAN6DQoWOEYAuClwwBzANzr0KAGKQcAMxsi9TLFkilwsUwF9BgkEQ5ojFgA7sLi5ADCHKDK0mRySFCgAGSqZgD67HoA5MTs2QA0oH4APAC0oOyU5AAm8CiE3IgYHFgENm3+7GZBwXoAFACUMQB8+tywJoLevmA1WIZoLHgA1mESoAAiCzGgcaQJCilpGpk584aFxWDlldWgdQ1NLeydHQQXZssrA8OKYygDJMvD5RBtDkllFF2KAAD5bBY+QhYWCA0DBSj1FakPAoPTQ3ZqU5ZUC5DiFMxaXSkgDqmJQ2NxFI09Sstnsei4OFIBR6pBCv1GpIAsgBRADyNKlAEJstdQHSsTjAvzgmhILgapARNMkSi0WIcGIJHg9NtDISMiTshdmZptKQcgAFI0mu2s6x2BygGyoHlfGg-UBDIXZcDBZxYOV+F3GnGgahocCgQykWDsVwQCNYdCo-jgGrYGwQUAanCF766wTI1EuUgAOg1hn6GKVuPrvSGwz8ZTGACIxZKZX3q-q642Fv1DXG8PXvl35b3QH3w5GR6O8xAUGQ8OwAHKkABu8eU-VgelgR5xgwvV4I-xOdzwIU0pGCoFFeGfeH62QAypQuCQIWl7HgQ1BxrA2SDFWNZosg2J7lg9TkKe7iJJAegQpAN7jEYQpEhQwTwOwhCUMG6EKPWmTDIRGjEGQpJ5NkOhmBoGi0Ow+CYJRUAdqqQymOx-iMTaCwsWx7GcdxcAYXOgaCZJNSkL6OCQFkkkcaQXF4Dx244vud79LxOFCaA3gzHB45Nv0CGkEhKEtvSjIoIM3ZgEuA4SlKNLSiOVmuBOzZ2Q5ZBTq617uaAnmrs4I5AA" rel="noopener noreferrer"&gt;The solution code as a whole can be found here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical example – async HTTP states
&lt;/h2&gt;

&lt;p&gt;While the previous example was hopefully illustrative, we rarely write code about cats and dogs. A more useful and complete example could be the familiar situation in SPA applications fetching data: rendering the different states.&lt;/p&gt;

&lt;p&gt;Our imaginary application starts with a clean state, then performs an asynchronous HTTP API call to fetch some data, and then renders the resulting success or error based on what happened with the request. Here's a minimal example:&lt;/p&gt;

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

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Data&lt;/span&gt; &lt;span class="o"&gt;=&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;State&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;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;initial&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&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;_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;As you can see, we can &lt;em&gt;enumerate&lt;/em&gt; the different known states using discriminated unions. This way, when we write the rendering logic, we don't need to do any "if data then do something with data" type of checking. Instead we can just check for the value of &lt;code&gt;_t&lt;/code&gt;, and the compiler knows to narrow it down based on that. &lt;/p&gt;

&lt;p&gt;Note again that &lt;code&gt;_t&lt;/code&gt; could be called anything else too, as long as the name is consistent between the variants. In this case another example of a sensible discriminator name could be &lt;code&gt;status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The example is in react, but could be done in any other rendering pattern as well.&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;State&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;initial&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&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;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Oops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;happened&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&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="nx"&gt;p&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;/p&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&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Here&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s your data:&amp;lt;/h3&amp;gt;
            &amp;lt;ol&amp;gt;
              {state.data.items.map((i) =&amp;gt; (
                &amp;lt;li key={i}&amp;gt;{i}&amp;lt;/li&amp;gt;
              ))}
            &amp;lt;/ol&amp;gt;
          &amp;lt;/div&amp;gt;
        );
    }
  }


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Here's the full working example in CodeSandbox: &lt;a href="https://codesandbox.io/s/typescript-discriminate-unions-in-async-state-rendering-l2jbdl?file=/src/App.tsx" rel="noopener noreferrer"&gt;https://codesandbox.io/s/typescript-discriminate-unions-in-async-state-rendering-l2jbdl?file=/src/App.tsx&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Other use cases
&lt;/h2&gt;

&lt;p&gt;I have found discriminated unions especially helpful in situations where the result of an operation needs to be categorized into a success of a failure on a high level (hint: the &lt;a href="https://gcanti.github.io/fp-ts/modules/Either.ts.html" rel="noopener noreferrer"&gt;Either monad&lt;/a&gt; is a super useful pattern), and the different variants of successes and/or failures categorized even deeper. So think something like:&lt;/p&gt;

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

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Failure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;LogicFailure&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;DatabaseFailure&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;Success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SuccessWithData&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;SuccessWithoutData&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;Result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Failure&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You can see how the discriminated union pattern helps us compose the larger data types out of smaller enumerated pieces, and build the logic around what happens when each small piece is handled. This is useful for representing expected different outcomes of functions instead of throwing errors, and &lt;a href="https://dev.to/anttispitkanen/typescript-why-you-shouldnt-throw-errors-to-control-the-program-flow-3g91"&gt;this is discussed more in a separate post of mine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is also very useful for the purpose of building observability into the different variants, for example categorizing what kinds of errors are encountered. More on that in a separate post later.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>architecture</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Reliability Restaurant – How to approach software reliability as a mindset</title>
      <dc:creator>Antti Pitkänen</dc:creator>
      <pubDate>Sat, 16 Apr 2022 16:52:21 +0000</pubDate>
      <link>https://forem.com/anttispitkanen/reliability-restaurant-how-to-approach-software-reliability-as-a-mindset-3656</link>
      <guid>https://forem.com/anttispitkanen/reliability-restaurant-how-to-approach-software-reliability-as-a-mindset-3656</guid>
      <description>&lt;p&gt;&lt;em&gt;Photograph by &lt;strong&gt;Life Of Pix&lt;/strong&gt; from &lt;strong&gt;Pexels&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is software reliability?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.sciencedirect.com/science/article/abs/pii/S0065245808602995"&gt;ScienceDirect&lt;/a&gt; defines software reliability as follows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Software reliability is the probability of failure-free operation of a computer program for a specified period in a specified environment. Reliability is a customer-oriented view of software quality. It relates to operation rather than design of the program, and hence it is dynamic rather than static.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another closely related term is resiliency, as defined by &lt;a href="https://www.microsoft.com/security/blog/2014/03/24/reliability-series-1-reliability-vs-resilience/"&gt;Microsoft&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Resiliency is the ability of a [...] service to withstand certain types of failure and yet remain functional from the customer perspective. In other words, reliability is the outcome and resilience is the way you achieve the outcome.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So for the sake of simplicity let's discuss reliability without specifying resiliency explicitly, we can assume it to be the other side of the coin implicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about a restaurant?
&lt;/h2&gt;

&lt;p&gt;Reliability, like security, has much less to do with using the correct frameworks and libraries than with asking the right questions and having the right mindset. For the sake of discussing the principles rather than specifics, let's use a metaphor of a pancake restaurant rather than some computer program. Everyone knows what a restaurant does, and can imagine what &lt;strong&gt;failure-free operation&lt;/strong&gt; looks like for one. The same mindset can then be applied to software systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why care about reliability?
&lt;/h2&gt;

&lt;p&gt;Looking at the definition of reliability, it seems like the thing to do to achieve "failure-free operation" is to avoid failure at any cost. But anyone who's ever written software knows that even with careful writing, reviewing and testing, bugs still manage to find their way to production regularly. More generally speaking, unexpected things and mistakes of different kinds are always bound to happen regardless of the activity, especially at scale. It's safe to assume that our pancake restaurant will run into some problems and failures in its operations, no matter the amount of planning and trying to avoid them.&lt;/p&gt;

&lt;p&gt;If failure is inevitable, why talk about failure-free operation then? The definition of failure matters. Reliability is all about constructing the bigger system so that individual failures can be tolerated and recovered from, without failure to the overall system.&lt;/p&gt;

&lt;p&gt;From a business owner's perspective, you want your system to be able to &lt;strong&gt;provide business value&lt;/strong&gt; even if some component fails, instead of the whole system being rendered useless. If &lt;em&gt;something&lt;/em&gt; fails, you want to be able to work around it. In the restaurant, if someone drops and breaks a plate – a failure – you don't want to have to close the restaurant as a result. Instead you want to be able to tolerate and work around such failures, keep the doors open, serve paying customers, and have your business running. Likewise you don't want every error to take your whole software system down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining "failure-free operation" for a pancake restaurant
&lt;/h2&gt;

&lt;p&gt;The properties of an operational restaurant are pretty much obvious, but worth listing explicitly for the sake of the example. So let's say that the restaurant must be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take in customers and seat them in tables&lt;/li&gt;
&lt;li&gt;Take orders from them&lt;/li&gt;
&lt;li&gt;Prepare the dishes as ordered&lt;/li&gt;
&lt;li&gt;Serve the food to the customers&lt;/li&gt;
&lt;li&gt;Charge money from the customers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's keep it simple and limit the requirements to these five things. Looks kind of like a &lt;a href="https://en.wikipedia.org/wiki/User_story"&gt;user story&lt;/a&gt;, doesn't it?&lt;/p&gt;

&lt;p&gt;Now it's fairly easy to map out the &lt;strong&gt;best case scenario&lt;/strong&gt;, or &lt;a href="https://en.wikipedia.org/wiki/Happy_path"&gt;happy path&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A customer walks in to the restaurant and sits at a table 🪑&lt;/li&gt;
&lt;li&gt;The waiter goes and gets their order – pancakes 🥞 – and takes that info to the kitchen&lt;/li&gt;
&lt;li&gt;The chef prepares a plate of delicious pancakes, all the ingredients are there readily available 🧑‍🍳&lt;/li&gt;
&lt;li&gt;The waiter takes the pancakes to the customer to eat 🍽&lt;/li&gt;
&lt;li&gt;After dining, the customer orders the check, pays for the food, and leaves happy 😋&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To serve the one customer, only one waiter and one chef are needed, so let's say there are no more employees around. All seems good, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Diverting from the happy path – remaining operational under unexpected circumstances
&lt;/h2&gt;

&lt;p&gt;The happy path looks simple enough. But what if something different happens? Let's say that Elon Musk tweets about the best pancakes he ever had at your restaurant (the customer was Elon Musk the whole time, bet you didn't see that coming! 😳), and the next day 10,000 people want to come try those pancakes.&lt;/p&gt;

&lt;p&gt;Now what if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All the people rush in at the same time?&lt;/li&gt;
&lt;li&gt;Someone orders something that the chef doesn't know how to make?&lt;/li&gt;
&lt;li&gt;Some ingredient runs out in the kitchen?&lt;/li&gt;
&lt;li&gt;Some ingredient deliveries get cancelled due to the supplier?&lt;/li&gt;
&lt;li&gt;The waiter or chef is out sick?&lt;/li&gt;
&lt;li&gt;A batch of pancakes falls on the floor in the kitchen, requiring cleaning before cooking can resume?&lt;/li&gt;
&lt;li&gt;People try to pay, but your card reader device isn't working?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's hard to imagine the happy path working under these circumstances, so let's look at the things one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overflow of customers
&lt;/h3&gt;

&lt;p&gt;The restaurant can hardly operate in a satisfactory way if people march in and try to seat themselves uncontrollably, especially when the amount of people greatly exceeds the restaurant's seating capacity. What can be done?&lt;/p&gt;

&lt;p&gt;A simple reliability mechanism that the restaurant can apply is instructing the customers to &lt;strong&gt;wait to be seated&lt;/strong&gt;, and &lt;strong&gt;queue&lt;/strong&gt; for that. This way the customers wait at the door or lobby in an ordered queue based on the order they arrived, and the restaurant (in this example probably the waiter) controls the way and rate in which that they get seated in tables. Some delay can be added to make time for cleaning the tables after the previous customers, resulting in much better customer experience. This is analogous to &lt;strong&gt;throttling&lt;/strong&gt; and &lt;strong&gt;queuing&lt;/strong&gt; in software.&lt;/p&gt;

&lt;p&gt;If there are simply too many customers coming in for the restaurant to handle, the waiter can &lt;strong&gt;turn them away at the door&lt;/strong&gt; and ask them to come back later. Not the best customer experience for sure, but this kind of expectation management is better for everyone than seating them and not being able to serve them. By only taking in the amount of customers the restaurant can handle, we can make sure to remain operational for those customers that we do take in. This is analogous to &lt;strong&gt;rate limiting&lt;/strong&gt; in software – don't take in more requests than you can properly handle.&lt;/p&gt;

&lt;p&gt;How to avoid having to turn people away at the door? Enter &lt;strong&gt;table reservations&lt;/strong&gt;. This way the restaurant can control the amount and rate of customers ahead of time, and expectation management is even better for the customers, as it's nicer to be turned away at the phone, rather than after already walking to the restaurant. This is analogous to &lt;strong&gt;planned capacity&lt;/strong&gt;, or &lt;strong&gt;scheduling&lt;/strong&gt;, in software.&lt;/p&gt;

&lt;p&gt;Note that it is possible and maybe even desirable to apply these same mechanisms also later on in the flow. For example the kitchen can take in orders as a queue and work on the dishes one at a time to control the work pressure for the chef. In general however it's good to apply these mechanisms as early in the flow as possible. It's better to have the whole restaurant serve a manageable amount of customers at once, than to have the dining room overflowing from hungry people while just the kitchen can work at a controlled pace.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unexpected orders
&lt;/h3&gt;

&lt;p&gt;Now that we have limited the amount of customers to serve at any given time, all seems to be good. But what if someone orders waffles instead of pancakes, and our kitchen lacks the required gear, ingredients or expertise to make waffles?&lt;/p&gt;

&lt;p&gt;You can imagine what would happen to the kitchen's ability to produce dishes if the chef needs to start by looking up a recipe and going out to buy the needed ingredients and a waffle iron. Contrast that to having the chef know the recipe already, and having all that's needed for cooking it readily available in the kitchen.&lt;/p&gt;

&lt;p&gt;So what's the reliability mechanism that can be applied here? Having a &lt;strong&gt;menu&lt;/strong&gt; and only serving dishes from the menu. This is a way of managing the expectations for the chef and kitchen. It's much easier to prepare with the necessary knowhow, devices and ingredients, when the dishes that can be ordered are listed ahead of time and no surprises can happen. The software analogy here is a bit more vague, but think &lt;strong&gt;allowlisting inputs&lt;/strong&gt; to limit what kind of requests are taken in for handling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ingredients running out
&lt;/h3&gt;

&lt;p&gt;The amount of customers and unexpected orders are handled, but what happens if the kitchen runs out of flour during opening hours? Surely that will limit the capability of making pancakes.&lt;/p&gt;

&lt;p&gt;In the happy path example it might be good enough to go to the supermarket next door to buy the ingredients for a single serving of pancakes only when the order arrives (the equivalent of &lt;strong&gt;lazy evaluation&lt;/strong&gt;, &lt;strong&gt;just in time computation&lt;/strong&gt;, or &lt;strong&gt;on demand fetching&lt;/strong&gt; in software). Let's make an assumption that this won't take more than a couple of minutes. Not that this sounds like a reasonable thing for a restaurant's kitchen, but it would be doable. It starts to get less tolerable when the amount of customers and the expected throughput of pancakes in the kitchen is expected to grow. &lt;/p&gt;

&lt;p&gt;At full service it might be catastrophic to the restaurant's operation (remember, being able to serve pancakes to paying customers in reasonable time) to run out of an important ingredient. So it makes sense to &lt;strong&gt;stock up&lt;/strong&gt; with all the necessary ingredients in preparation for a day's work.&lt;/p&gt;

&lt;p&gt;The software analogy is again not 100% accurate, but think &lt;strong&gt;caching&lt;/strong&gt;. Instead of having to repeatedly read data from a database or API, or perform a repeated intensive computation, caching the results in memory allows much faster serving of responses back downstream.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supplier cancelling
&lt;/h3&gt;

&lt;p&gt;Due to various reasons such as limited storage space and ingredients expiring, it's not possible to stock up indefinitely. So regardless of preparations, new ingredients are continuously needed, maybe even during the opening hours.&lt;/p&gt;

&lt;p&gt;What happens if the supplier calls to say that their delivery truck has a flat tire, and they cannot deliver the much needed flour? The kitchen will run out in one hour if new flour isn't received somehow.&lt;/p&gt;

&lt;p&gt;To solve this problem the restaurant needs some kind of &lt;strong&gt;backup&lt;/strong&gt;. Maybe the chef will make a run to the supermarket next door, as some delay in the kitchen is better than not being able to serve pancakes at all. Or maybe the restaurant has a backup supplier that they can call in a situation like this.&lt;/p&gt;

&lt;p&gt;The software analogy is &lt;strong&gt;backups&lt;/strong&gt;, &lt;strong&gt;replication&lt;/strong&gt; and &lt;strong&gt;failover&lt;/strong&gt;, all parts of the wider concept of &lt;strong&gt;high availability (HA)&lt;/strong&gt;. If you only have one database instance and it shuts down, your service cannot remain operational. But if you have a system that can automatically failover to a working database instance, the system can remain operational with minimal downtime. Note that you would need data replication for this to be feasible. Likewise you can run multiple parallel instances of your stateless application servers and balance the load between those, so that one application server failing won't disrupt the system's overall operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Waiter or chef being out sick
&lt;/h3&gt;

&lt;p&gt;If there's just one waiter and one chef, either of them being out sick would be a major blocker for the restaurant's operation. Without a waiter no pancakes can be served to customers, and without a chef there are no pancakes to serve. We can safely identify both the waiter and the chef as a &lt;strong&gt;single point of failure (SPOF)&lt;/strong&gt; for the restaurant's operation.&lt;/p&gt;

&lt;p&gt;The obvious solution is to have multiple waiters and chefs working, or active backups for them that you can call in to work when needed – think &lt;strong&gt;high availability&lt;/strong&gt;. We'll look at the financial implications at the end of this post, but it's obvious that there's a limit to how many waiters and chefs the restaurant can afford to have in rotation. So let's look at other potential solutions as well.&lt;/p&gt;

&lt;p&gt;If the waiter is out sick, maybe the restaurant can try a form of self-service instead. Have the customers come make orders at the kitchen counter, and fetch the dishes from the kitchen when they are done, instead of waiting to be served. The payments can also be handled at the kitchen counter. Looks a little like how most fast food restaurants operate.&lt;/p&gt;

&lt;p&gt;If the chef is out sick, maybe the restaurant can serve pre-made pancakes that only need heating, that can be handled by the waiter in a microwave. Definitely not as good as fresh ones, but perhaps better than nothing. Or maybe serve only drinks if pancakes cannot be cooked. Again, not what the customers expect, but maybe better than turning them away at the door, both for thirsty customers and the business.&lt;/p&gt;

&lt;p&gt;Both of these examples are naive and not something that would make for a good experience, if the customers expect to be served fresh pancakes directly to the tables. In reality both of these examples are also such that they would require planning and implementation ahead of time to be feasible. But they both represent a way of working that's somehow "less" than the optimal, but still working to some extent, instead of being completely shut down.&lt;/p&gt;

&lt;p&gt;The software analogy is &lt;strong&gt;partial, graceful failure&lt;/strong&gt;. It depends on the case to what extent this is possible to implement, but in general you want to &lt;strong&gt;limit the blast radius&lt;/strong&gt; of any single point of failure so that a failure won't render the whole system unusable. If nothing else, you probably want to catch errors and show the users something human readable, instead of blank screens or stack traces. Or maybe you want to show cached data if fresh data cannot be fetched. Or if your website cannot load images, maybe you want to have some placeholders instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pancakes falling on the kitchen floor requiring cleaning
&lt;/h3&gt;

&lt;p&gt;No matter how skilled and careful the chef is, accidents can and will happen. During the busiest hour, a fresh batch of pancakes falls on the kitchen floor, causing a big mess. Nothing catastrophic, but those pancakes obviously cannot be served to customers, and they need to be cleaned to avoid slipping. This means a delay for pancakes being served, and the chef needs to clean the kitchen before continuing cooking – time to recover.&lt;/p&gt;

&lt;p&gt;Let's say the chef needs 10 minutes for cleaning. It's best that the waiter doesn't take in any new orders during that time. This way the chef gets to focus on cleaning instead of trying to multitask, and can start cooking again after that is done. As the customers will experience a delay in getting food, maybe the waiter can serve them drinks in the meanwhile instead. After the ten minutes needed for cleaning is passed, the waiter can check if the chef is ready, and if so, start taking in orders again. &lt;/p&gt;

&lt;p&gt;The same tactic can be applied also if the kitchen gets a large batch of orders that will take a while to cook – maybe it's better not to take in more orders before those already placed have been finished. Easing the built-up pressure in the short term can be a lot more effective than constantly working under high pressure. Sometimes it's necessary to get some time dedicated fully for recovery.&lt;/p&gt;

&lt;p&gt;This is analogous to &lt;strong&gt;circuit breakers&lt;/strong&gt; in software. In this example the waiter represents a downstream client, and the chef an upstream server. The pattern is about closing the client (waiter) from making new requests (orders) to the server (chef) if a certain error condition (needing to clean the floor) is met.&lt;/p&gt;

&lt;p&gt;Note that a circuit breaker is implemented specifically on the client's side. So in this example, if the chef has told the waiter they need 10 minutes of downtime for cleaning up, the waiter will not go to the kitchen counter with new orders for the next 10 minutes at all, but knows to wait. If a customer wants to place an order, the waiter can instantly inform them of the delay without asking the chef, and can offer drinks instead, promising to come back to the food subject in 10 minutes.&lt;/p&gt;

&lt;p&gt;Compare this to server side patterns such as timeouts and queues, where the waiter would go to the kitchen counter for every new customer order, and be told to wait by the chef. The advantage of the circuit breaker pattern is that the chef doesn't need to respond to the queries for new orders at all during the 10 minutes, and can fully focus on recovering the situation, that is, cleaning the mess in this example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Payments not working
&lt;/h3&gt;

&lt;p&gt;Everything has gone well for the customers: the mood was on point, service top notch and pancakes absolutely delicious. All that's left is paying the bill, but alas, the card reader doesn't work.&lt;/p&gt;

&lt;p&gt;While the customers might enjoy getting their food for free, that would certainly be undesirable for the restaurant. Remember, the happy path requires being able to charge money from the customers, otherwise the restaurant is hardly feasible business.&lt;/p&gt;

&lt;p&gt;As for the actual card reader device malfunctioning, maybe you can have a backup reader available. Or if the problem is batteries running out, at least have spare batteries at hand. High availability again. &lt;/p&gt;

&lt;p&gt;But maybe the problem is at the card processor's end, meaning that no amount of actions from the restaurant's side could avoid or solve that failure. In such a case you most likely want to have some backup way of collecting payments from the customers. Maybe you can take payments in cash, or even open a tab if you trust the customers to come back later to pay the bill.&lt;/p&gt;

&lt;p&gt;In this example the card processor is a &lt;strong&gt;dependency&lt;/strong&gt;, and specifically an external dependency. External, meaning that you cannot affect the reliability of the dependency itself, only how you build your system to depend on it. In this case you can &lt;strong&gt;mitigate the risk&lt;/strong&gt; of the dependency failing by introducing backup mechanisms (cash or tabs). The same concepts of high availability apply as described earlier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare for the unexpected... by expecting it
&lt;/h2&gt;

&lt;p&gt;When something unexpected happens, the restaurant staff can creatively improvise and adapt to the situation, work around it, and keep the business running. Computers however, &lt;a href="https://twitter.com/BecomingCritter/status/1511808623256682504?s=20&amp;amp;t=o5B-KCo0yYIkWDgDbSQv-Q"&gt;despite some promising developments&lt;/a&gt;, tend to be less capable of creativity or improvising, and more capable of following precise orders, given as the source code and other artefacts by the programmers. So the burden of creativity must remain mostly on the programmer.&lt;/p&gt;

&lt;p&gt;In order for your software to be able to handle unexpected situations, you have to build it as such. And in order to be able to build in the necessary reliability mechanisms for different situations, you must be able to creatively think about the different situations that might occur. Instead of trying to avoid failures altogether, build your system to be able to tolerate failure and recover from them. Avoid single points of failure, reduce the blast radius of any potential pieces failing, and don't forget high availability where it makes sense. Keep the happy path in mind.&lt;/p&gt;

&lt;p&gt;I hope that the restaurant metaphor can help to think about reliability holistically when designing your software systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability is a spectrum, SRE makes sense of the spectrum
&lt;/h2&gt;

&lt;p&gt;Reliability is not a binary thing that you either have or don't, but rather a spectrum. It's largely a business decision to decide how reliable your system should be. A pacemaker can't really afford to fail, or a plane in-flight system for that matter, but most systems don't work under such high pressure. &lt;/p&gt;

&lt;p&gt;Maybe it makes more financial sense to occasionally close our restaurant for a day than to keep extra staff on the payroll. Or if there is high demand for pancakes, maybe it makes sense to expand to a second location, creating a high availability setup for the whole business. Now if the other restaurant needs to be closed due to, say, a fire in the kitchen, the business as a whole can still operate as the other restaurant can serve customers.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Site_reliability_engineering"&gt;Site Reliability Engineering (SRE)&lt;/a&gt; methodology aims to make reliability an explicit goal for the business, and puts emphasis on the "reliable enough" part. When explicit &lt;a href="https://en.wikipedia.org/wiki/Service-level_objective"&gt;Service Level Objectives (SLOs)&lt;/a&gt; are set, those can be used to drive the development efforts in a way that's reliable enough for the business, but not more than that. As discussed it doesn't make sense to invest more money in reliability than it, well, makes sense.&lt;/p&gt;

&lt;p&gt;For our pancake restaurant, we defined earlier that we want to be able to serve our customers their pancakes in a reasonable time. Let's make "reasonable time" explicit and set an SLO: we want 99% of our customers to receive their pancakes within 15 minutes of ordering. Let's track this by measuring the time from ordering to the pancakes being served for every order.&lt;/p&gt;

&lt;p&gt;If we are lagging badly behind our target, we need to do something about it (or re-evaluate the target itself, but let's assume the target is good for now). We can speed up the orders in many ways, for example by having two chefs and two waiters working at all times. If this takes our SLO to the desired level, we know that this is good enough. By employing even more chefs and waiters we might be able to make the orders even faster, but since we have reached our reliability target (and assuming our target is sensible), it doesn't make sense to invest more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Building a reliable system is not about following a step by step guide, but rather about being able to think creatively about your system and the different conditions it can face. There's no clear, generalizable one-to-one mapping between the examples given here and your system, but with creative thinking you should be able to identify the "chefs and waiters" or your system, and more. The examples also serve as direction on how to approach applying the various kinds of reliability mechanisms.&lt;/p&gt;

&lt;p&gt;Hopefully this helps you build your system as reliable and resilient.&lt;/p&gt;

</description>
      <category>reliability</category>
      <category>architecture</category>
      <category>systems</category>
      <category>systemdesign</category>
    </item>
  </channel>
</rss>
