summaryrefslogtreecommitdiff
path: root/2023/04/30
diff options
context:
space:
mode:
authormuqiuhan <[email protected]>2025-09-09 06:17:00 +0000
committermuqiuhan <[email protected]>2025-09-09 06:17:00 +0000
commitd5de65fdb1802cdf498d65d93397f290813c377c (patch)
tree92fe61a76d20d1203203665d4b48e7f151f088bd /2023/04/30
parent48efa2dfde7c263f84ee5bb0872747034908d607 (diff)
downloadblog-d5de65fdb1802cdf498d65d93397f290813c377c.tar.gz
deploy: 9665097f0fa0dae9f92123fac54d26c0818758a5
Diffstat (limited to '2023/04/30')
-rw-r--r--2023/04/30/TypeScript-With-Rust-Errors-No-Try-Catch-Heresy/index.html12
1 files changed, 3 insertions, 9 deletions
diff --git a/2023/04/30/TypeScript-With-Rust-Errors-No-Try-Catch-Heresy/index.html b/2023/04/30/TypeScript-With-Rust-Errors-No-Try-Catch-Heresy/index.html
index b02ebb78..81aa9750 100644
--- a/2023/04/30/TypeScript-With-Rust-Errors-No-Try-Catch-Heresy/index.html
+++ b/2023/04/30/TypeScript-With-Rust-Errors-No-Try-Catch-Heresy/index.html
@@ -197,32 +197,26 @@
</blockquote>
<p>The first problem is, and personally, I believe it’s the biggest JavaScript problem ever: we don’t know what can throw an error. From a JavaScript error perspective, it’s the same as the following:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="keyword">let</span> data = “<span class="title class_">Hello</span>”;</span><br><span class="line">&#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(err);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
-
<p>JavaScript doesn’t know; JavaScript doesn’t care. You should know.</p>
<p>Second thing, this is perfectly viable code:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> request = &#123; <span class="attr">name</span>: “test”, <span class="attr">value</span>: <span class="number">2n</span> &#125;;</span><br><span class="line"><span class="keyword">const</span> body = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(request);</span><br><span class="line"><span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">&quot;https://example.com&quot;</span>, &#123;</span><br><span class="line"> <span class="attr">method</span>: “<span class="variable constant_">POST</span>”,</span><br><span class="line"> body,</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">if</span> (!response.<span class="property">ok</span>) &#123;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
-
<p>No errors, no linters, even though this can break your app.</p>
-<p>Right now, in my head, I can hear, “What’s the problem, just use try&#x2F;catch everywhere.” Here comes the third problem: we don’t know which one is thrown. Of course, we can somehow guess by the error message, but what about bigger services&#x2F;functions with many places where errors can happen? Are you sure you are handling all of them properly with one try&#x2F;catch?</p>
+<p>Right now, in my head, I can hear, “What’s the problem, just use try/catch everywhere.” Here comes the third problem: we don’t know which one is thrown. Of course, we can somehow guess by the error message, but what about bigger services/functions with many places where errors can happen? Are you sure you are handling all of them properly with one try/catch?</p>
<hr>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="variable">greeting_file_result</span> = File::<span class="title function_ invoke__">open</span>(“hello.txt”); </span><br><span class="line"><span class="keyword">let</span> <span class="variable">greeting_file</span> = <span class="keyword">match</span> greeting_file_result &#123; </span><br><span class="line"> <span class="title function_ invoke__">Ok</span>(file) =&gt; file, </span><br><span class="line"> <span class="title function_ invoke__">Err</span>(error) =&gt; <span class="built_in">panic!</span>(<span class="string">&quot;Problem opening the file: &#123;:?&#125;&quot;</span>, error), </span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
-
<p>The most verbose of the three shown here and, ironically, the best one. So, first of all, Rust handles the errors using its amazing enums (they are not the same as TypeScript enums!). Without going into detail, what is important here is that it uses an enum called <code>Result</code> with two variants: <code>Ok</code> and <code>Err</code>. As you might guess, <code>Ok</code> holds a value and <code>Err</code> holds…surprise, an error :D.</p>
<p>The summary here is that Rust always know where there might be an error. And it force you to deal with it right where it appears (mostly). No hidden ones, no guessing, no breaking app with a surprise face.</p>
<p>And this approach is just better. By A MILE.</p>
<p>We cannot make TypeScript errors work like the Rust. The limiting factor here is the language itself; it doesn’t have the proper tools to do that.</p>
<p>But what we can do is try to make it similar. And make it simple:</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">type</span> <span class="title class_">Safe</span>&lt;T&gt; = </span><br><span class="line"> | &#123; </span><br><span class="line"> <span class="attr">success</span>: <span class="literal">true</span>; </span><br><span class="line"> <span class="attr">data</span>: T; </span><br><span class="line"> &#125; </span><br><span class="line"> | &#123; </span><br><span class="line"> <span class="attr">success</span>: <span class="literal">false</span>; </span><br><span class="line"> <span class="attr">error</span>: <span class="built_in">string</span>; </span><br><span class="line"> &#125;;</span><br></pre></td></tr></table></figure>
-
-<p>we do need a few try&#x2F;catches. The good thing is we only need about two, not 100,000:</p>
+<p>we do need a few try/catches. The good thing is we only need about two, not 100,000:</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> safe&lt;T&gt;(<span class="attr">promise</span>: <span class="title class_">Promise</span>&lt;T&gt;, <span class="attr">err</span>?: <span class="built_in">string</span>): <span class="title class_">Promise</span>&lt;<span class="title class_">Safe</span>&lt;T&gt;&gt;;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> safe&lt;T&gt;(<span class="attr">func</span>: <span class="function">() =&gt;</span> T, <span class="attr">err</span>?: <span class="built_in">string</span>): <span class="title class_">Safe</span>&lt;T&gt;;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> safe&lt;T&gt;(</span><br><span class="line"> <span class="attr">promiseOrFunc</span>: <span class="title class_">Promise</span>&lt;T&gt; | (<span class="function">() =&gt;</span> T),</span><br><span class="line"> <span class="attr">err</span>?: <span class="built_in">string</span>,</span><br><span class="line">): <span class="title class_">Promise</span>&lt;<span class="title class_">Safe</span>&lt;T&gt;&gt; | <span class="title class_">Safe</span>&lt;T&gt; &#123;</span><br><span class="line"> <span class="keyword">if</span> (promiseOrFunc <span class="keyword">instanceof</span> <span class="title class_">Promise</span>) &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">safeAsync</span>(promiseOrFunc, err);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">safeSync</span>(promiseOrFunc, err);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> safeAsync&lt;T&gt;(</span><br><span class="line"> <span class="attr">promise</span>: <span class="title class_">Promise</span>&lt;T&gt;, </span><br><span class="line"> <span class="attr">err</span>?: <span class="built_in">string</span></span><br><span class="line">): <span class="title class_">Promise</span>&lt;<span class="title class_">Safe</span>&lt;T&gt;&gt; &#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="keyword">const</span> data = <span class="keyword">await</span> promise;</span><br><span class="line"> <span class="keyword">return</span> &#123; data, <span class="attr">success</span>: <span class="literal">true</span> &#125;;</span><br><span class="line"> &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(e);</span><br><span class="line"> <span class="keyword">if</span> (err !== <span class="literal">undefined</span>) &#123;</span><br><span class="line"> <span class="keyword">return</span> &#123; <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: err &#125;;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">if</span> (e <span class="keyword">instanceof</span> <span class="title class_">Error</span>) &#123;</span><br><span class="line"> <span class="keyword">return</span> &#123; <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: e.<span class="property">message</span> &#125;;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> &#123; <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: <span class="string">&quot;Something went wrong&quot;</span> &#125;;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> safeSync&lt;T&gt;(</span><br><span class="line"> <span class="attr">func</span>: <span class="function">() =&gt;</span> T, </span><br><span class="line"> <span class="attr">err</span>?: <span class="built_in">string</span></span><br><span class="line">): <span class="title class_">Safe</span>&lt;T&gt; &#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="keyword">const</span> data = <span class="title function_">func</span>();</span><br><span class="line"> <span class="keyword">return</span> &#123; data, <span class="attr">success</span>: <span class="literal">true</span> &#125;;</span><br><span class="line"> &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(e);</span><br><span class="line"> <span class="keyword">if</span> (err !== <span class="literal">undefined</span>) &#123;</span><br><span class="line"> <span class="keyword">return</span> &#123; <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: err &#125;;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">if</span> (e <span class="keyword">instanceof</span> <span class="title class_">Error</span>) &#123;</span><br><span class="line"> <span class="keyword">return</span> &#123; <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: e.<span class="property">message</span> &#125;;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> &#123; <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: <span class="string">&quot;Something went wrong&quot;</span> &#125;;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
-
<p>This is just a wrapper with our <code>Safe</code> type as the return one. But sometimes simple things are all you need. Let’s combine them with the example from above.</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> request = &#123; <span class="attr">name</span>: “test”, <span class="attr">value</span>: <span class="number">2n</span> &#125;; </span><br><span class="line"><span class="keyword">const</span> body = <span class="title function_">safe</span>( </span><br><span class="line"> <span class="function">() =&gt;</span> <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(request), </span><br><span class="line"> “<span class="title class_">Failed</span> to serialize request”, </span><br><span class="line">); </span><br><span class="line"><span class="keyword">if</span> (!body.<span class="property">success</span>) &#123; </span><br><span class="line"> <span class="comment">// handle error (body.error) </span></span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">safe</span>( </span><br><span class="line"> <span class="title function_">fetch</span>(<span class="string">&quot;https://example.com&quot;</span>, &#123; </span><br><span class="line"> <span class="attr">method</span>: “<span class="variable constant_">POST</span>”, </span><br><span class="line"> <span class="attr">body</span>: body.<span class="property">data</span>, </span><br><span class="line"> &#125;), </span><br><span class="line">); </span><br><span class="line"><span class="keyword">if</span> (!response.<span class="property">success</span>) &#123; </span><br><span class="line"> <span class="comment">// handle error (response.error) </span></span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">if</span> (!response.<span class="property">data</span>.<span class="property">ok</span>) &#123; </span><br><span class="line"> <span class="comment">// handle network error </span></span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line">&#125; </span><br><span class="line"><span class="comment">// handle response (body.data)</span></span><br></pre></td></tr></table></figure>
-
<p>New solution is longer, but it performs better because of the following reasons:</p>
<ul>
-<li>no try&#x2F;catch</li>
+<li>no try/catch</li>
<li>we handle each error where it occurs</li>
<li>we can specify an error message for a specific function</li>
<li>we have a nice top-to-bottom logic, all errors on top, then only the response at the bottom</li>