Skip to content

Commit

Permalink
TS 5.5 post
Browse files Browse the repository at this point in the history
  • Loading branch information
danvk committed Jul 2, 2024
1 parent 62dae17 commit 5fc1d54
Show file tree
Hide file tree
Showing 13 changed files with 347 additions and 86 deletions.
2 changes: 1 addition & 1 deletion 2021/05/06/unsoundness/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ <h2 id="any"><a href="#any" class="headerlink" title="any"></a><code>any</code><
<p>If you &quot;put an <code>any</code> on it&quot;, then anything goes. The static types may or may not have anything to do with real runtime types:</p>
<figure class="highlight ts"><table><tr><td class="code"><pre><code class="hljs ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">alertNumber</span>(<span class="hljs-params">x: <span class="hljs-built_in">number</span></span>) </span>&#123;<br> alert(x.toFixed(<span class="hljs-number">1</span>)); <span class="hljs-comment">// static type of x is number, runtime type is string</span><br>&#125;<br><span class="hljs-keyword">const</span> num: <span class="hljs-built_in">any</span> = <span class="hljs-string">&#x27;forty two&#x27;</span>;<br>alertNumber(num);<br><span class="hljs-comment">// no error, throws at runtime:</span><br><span class="hljs-comment">// Cannot read property &#x27;toFixed&#x27; of undefined</span><br></code></pre></td></tr></table></figure>

<p>The solution here is simple: limit your use of <code>any</code> or, better, don&#39;t use it at all! Chapter 5 of <a target="_blank" rel="noopener" href="https://amzn.to/3HIrQN6" onclick="return trackOutboundLink('any', 'https://amzn.to/3HIrQN6', event);">Effective TypeScript</a> is all about how to mitigate and avoid the static type disaster that is <code>any</code>. The highlights are to limit the scope of <code>any</code> and to use <code>unknown</code> as a safer alternative when possible.</p>
<p>The solution here is simple: limit your use of <code>any</code> or, better, don&#39;t use it at all! Chapter 5 of <a target="_blank" rel="noopener" href="https://amzn.to/3UjPrsK" onclick="return trackOutboundLink('any', 'https://amzn.to/3UjPrsK', event);">Effective TypeScript</a> is all about how to mitigate and avoid the static type disaster that is <code>any</code>. The highlights are to limit the scope of <code>any</code> and to use <code>unknown</code> as a safer alternative when possible.</p>
<h2 id="Type-Assertions"><a href="#Type-Assertions" class="headerlink" title="Type Assertions"></a>Type Assertions</h2><p><strong>How often does this occur?</strong> Often (though not as often as object and array lookups).</p>
<p>The slightly less offensive cousin of <code>any</code> is the &quot;type assertion&quot; (<em>not</em> the &quot;cast&quot;, see my <a href="https://effectivetypescript.com/2021/02/03/pet-peeves/">rant on this terminology</a>):</p>
<figure class="highlight ts"><table><tr><td class="code"><pre><code class="hljs ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">alertNumber</span>(<span class="hljs-params">x: <span class="hljs-built_in">number</span></span>) </span>&#123;<br> alert(x.toFixed(<span class="hljs-number">1</span>));<br>&#125;<br><span class="hljs-keyword">const</span> x1 = <span class="hljs-built_in">Math</span>.random() || <span class="hljs-literal">null</span>; <span class="hljs-comment">// type is number | null</span><br>alertNumber(x1);<br><span class="hljs-comment">// ~~ ... Type &#x27;null&#x27; is not assignable to type &#x27;number&#x27;.</span><br>alertNumber(x1 <span class="hljs-keyword">as</span> <span class="hljs-built_in">number</span>); <span class="hljs-comment">// type checks, but might blow up at runtime</span><br></code></pre></td></tr></table></figure>
Expand Down
2 changes: 1 addition & 1 deletion 2022/04/18/twitch-expect-type/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ <h2>My Twitch Debut (eslint-plugin-expect-type with Josh Goldberg)</h2>
<li>It&#39;s implemented through an eslint plugin, so you don&#39;t need another tool to make type assertions.</li>
<li>It has an autofixer, which makes this pleasant to use.</li>
</ol>
<p>Once the PR is merged, this will be my new preferred way to test types, and I&#39;ll have to update the recommendations from my <a target="_blank" rel="noopener" href="https://www.youtube.com/watch?v=nygcFEwOG8w" onclick="return trackOutboundLink('my twitch debut eslintpluginexpecttype with josh goldberg', 'https://www.youtube.com/watch?v=nygcFEwOG8w', event);">TSConf 2019 talk</a> as well as Item 52 in <a target="_blank" rel="noopener" href="https://amzn.to/3HIrQN6" onclick="return trackOutboundLink('my twitch debut eslintpluginexpecttype with josh goldberg', 'https://amzn.to/3HIrQN6', event);"><em>Effective TypeScript</em></a> (&quot;Be Aware of the Pitfalls of Testing Types&quot;). I&#39;m already using it on my latest open source project, <a target="_blank" rel="noopener" href="https://github.com/danvk/crudely-typed/" onclick="return trackOutboundLink('my twitch debut eslintpluginexpecttype with josh goldberg', 'https://github.com/danvk/crudely-typed/', event);">crudely-typed</a> (more on that soon!).</p>
<p>Once the PR is merged, this will be my new preferred way to test types, and I&#39;ll have to update the recommendations from my <a target="_blank" rel="noopener" href="https://www.youtube.com/watch?v=nygcFEwOG8w" onclick="return trackOutboundLink('my twitch debut eslintpluginexpecttype with josh goldberg', 'https://www.youtube.com/watch?v=nygcFEwOG8w', event);">TSConf 2019 talk</a> as well as Item 52 in <a target="_blank" rel="noopener" href="https://amzn.to/3UjPrsK" onclick="return trackOutboundLink('my twitch debut eslintpluginexpecttype with josh goldberg', 'https://amzn.to/3UjPrsK', event);"><em>Effective TypeScript</em></a> (&quot;Be Aware of the Pitfalls of Testing Types&quot;). I&#39;m already using it on my latest open source project, <a target="_blank" rel="noopener" href="https://github.com/danvk/crudely-typed/" onclick="return trackOutboundLink('my twitch debut eslintpluginexpecttype with josh goldberg', 'https://github.com/danvk/crudely-typed/', event);">crudely-typed</a> (more on that soon!).</p>
<p>I had a great time chatting with Josh, and I think we both learned a thing or two. Hopefully you will, too!</p>
<!-- Add a placeholder for the Twitch embed -->
<div id="twitch-embed"></div>
Expand Down
2 changes: 1 addition & 1 deletion 2022/05/28/eslint-plugin-expect-type/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ <h2>A new way to test types</h2>
</time>
</div>
<div class="entry-content">
<p>Readers of <a target="_blank" rel="noopener" href="https://amzn.to/3HIrQN6" onclick="return trackOutboundLink('a new way to test types', 'https://amzn.to/3HIrQN6', event);">Effective TypeScript</a> and followers of this blog will know that testing types is a long-standing interest of mine:</p>
<p>Readers of <a target="_blank" rel="noopener" href="https://amzn.to/3UjPrsK" onclick="return trackOutboundLink('a new way to test types', 'https://amzn.to/3UjPrsK', event);">Effective TypeScript</a> and followers of this blog will know that testing types is a long-standing interest of mine:</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://github.com/danvk/typings-checker" onclick="return trackOutboundLink('a new way to test types', 'https://github.com/danvk/typings-checker', event);">typings-checker</a> (2017) implemented <code>$ExpectType</code> and <code>$ExpectError</code> directives and helped to influence <a target="_blank" rel="noopener" href="https://github.com/microsoft/DefinitelyTyped-tools/tree/master/packages/dtslint" onclick="return trackOutboundLink('a new way to test types', 'https://github.com/microsoft/DefinitelyTyped-tools/tree/master/packages/dtslint', event);">dtslint</a>, which is used to test types on DefinitelyTyped.</li>
<li>I gave a talk at TSConf 2019 entitled <a target="_blank" rel="noopener" href="https://www.youtube.com/watch?v=nygcFEwOG8w" onclick="return trackOutboundLink('a new way to test types', 'https://www.youtube.com/watch?v=nygcFEwOG8w', event);">Testing Types: An Introduction to dtslint</a>.</li>
Expand Down
2 changes: 1 addition & 1 deletion 2023/06/27/ts-51/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ <h2>Notes on TypeScript 5.1</h2>

<h2 id="Performance-Improvements"><a href="#Performance-Improvements" class="headerlink" title="Performance Improvements"></a>Performance Improvements</h2><p>When you hear &quot;new TypeScript version&quot;, the natural tendency is to think about new language features. But what would you be more excited about: an exciting new feature like <a href="https://effectivetypescript.com/2020/11/05/template-literal-types/">template literal types</a> or a 10% faster compiler? Sorry, you can&#39;t have both!</p>
<p>The TypeScript team takes compiler performance incredibly seriously and every single set of release notes includes a few performance optimizations. A recent theme has been improving build times for projects that use complex libraries like Material-UI. The 5.1 release includes several <a target="_blank" rel="noopener" href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-1/#optimizations" onclick="return trackOutboundLink('performance improvements', 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-1/#optimizations', event);">optimizations</a> that add up to a big win.</p>
<p>As readers of this blog may recall, <a target="_blank" rel="noopener" href="https://amzn.to/3HIrQN6" onclick="return trackOutboundLink('performance improvements', 'https://amzn.to/3HIrQN6', event);"><em>Effective TypeScript</em></a> is itself type-checked using <a href="https://effectivetypescript.com/2020/06/30/literate-ts/">literate-ts</a>. The idea is that when new versions of TypeScript come out, I can quickly check whether any of the hundreds of code samples in the book produce new and unexpected errors. This is a great confidence booster that my book still matches reality, but it also means that <em>Effective TypeScript</em> can serve as a good gauge of what&#39;s changed between releases.</p>
<p>As readers of this blog may recall, <a target="_blank" rel="noopener" href="https://amzn.to/3UjPrsK" onclick="return trackOutboundLink('performance improvements', 'https://amzn.to/3UjPrsK', event);"><em>Effective TypeScript</em></a> is itself type-checked using <a href="https://effectivetypescript.com/2020/06/30/literate-ts/">literate-ts</a>. The idea is that when new versions of TypeScript come out, I can quickly check whether any of the hundreds of code samples in the book produce new and unexpected errors. This is a great confidence booster that my book still matches reality, but it also means that <em>Effective TypeScript</em> can serve as a good gauge of what&#39;s changed between releases.</p>
<p>First let&#39;s look at performance:</p>
<ul>
<li>Checking Effective TypeScript (TS 5.0.4): 180.6s average</li>
Expand Down
2 changes: 1 addition & 1 deletion 2023/09/27/closure-compiler/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ <h2 id="What-is-the-Closure-Compiler"><a href="#What-is-the-Closure-Compiler" cl
<figure class="highlight plain"><table><tr><td class="code"><pre><code class="hljs plain">&gt; google-closure-compiler &quot;--warning_level&quot; &quot;VERBOSE&quot; &quot;max.js&quot;<br><br>max.js:12:16: WARNING - [JSC_TYPE_MISMATCH] actual parameter 1 of max does not match formal parameter<br>found : string<br>required: number<br> 12| console.log(max(&#39;foo&#39;, &#39;bar&#39;));<br> ^^^^^<br><br>max.js:12:23: WARNING - [JSC_TYPE_MISMATCH] actual parameter 2 of max does not match formal parameter<br>found : string<br>required: number<br> 12| console.log(max(&#39;foo&#39;, &#39;bar&#39;));<br> ^^^^^<br><br>0 error(s), 2 warning(s), 100.0% typed<br>function max(a,b)&#123;return a&gt;b?a:b&#125;console.log(max(&quot;foo&quot;,&quot;bar&quot;));<br></code></pre></td></tr></table></figure>

<p>This is similar to what <code>tsc</code> does in some ways but different in others. Just like <code>tsc</code>, it reports type errors in your code. And just like <code>tsc</code>, it outputs JavaScript (the last line). At a high level, type checking and JS emit are also the two things that TypeScript does.</p>
<p>There are some interesting differences, too. The Closure Compiler reports that our code is &quot;100.0% typed&quot;. Using TypeScript terminology, this is a measure of how many <code>any</code> types you have. (<a target="_blank" rel="noopener" href="https://amzn.to/3HIrQN6" onclick="return trackOutboundLink('what is the closure compiler', 'https://amzn.to/3HIrQN6', event);"><em>Effective TypeScript</em></a> discusses using the <a target="_blank" rel="noopener" href="https://github.com/plantain-00/type-coverage" onclick="return trackOutboundLink('what is the closure compiler', 'https://github.com/plantain-00/type-coverage', event);">type-coverage</a> tool to get this information in Item 44: Track Your Type Coverage to Prevent Regressions in Type Safety.)</p>
<p>There are some interesting differences, too. The Closure Compiler reports that our code is &quot;100.0% typed&quot;. Using TypeScript terminology, this is a measure of how many <code>any</code> types you have. (<a target="_blank" rel="noopener" href="https://amzn.to/3UjPrsK" onclick="return trackOutboundLink('what is the closure compiler', 'https://amzn.to/3UjPrsK', event);"><em>Effective TypeScript</em></a> discusses using the <a target="_blank" rel="noopener" href="https://github.com/plantain-00/type-coverage" onclick="return trackOutboundLink('what is the closure compiler', 'https://github.com/plantain-00/type-coverage', event);">type-coverage</a> tool to get this information in Item 44: Track Your Type Coverage to Prevent Regressions in Type Safety.)</p>
<p>The other interesting difference is that the output is minified. This gets us the fundamental design goal of the Closure Compiler: producing the smallest JavaScript possible.</p>
<h2 id="Minification-as-Design-Goal"><a href="#Minification-as-Design-Goal" class="headerlink" title="Minification as Design Goal"></a>Minification as Design Goal</h2><p>When Gmail came out back in 2004, network speeds were much, much slower than they are today. The Gmail team found that runtime JavaScript performance was almost irrelevant compared to download times (<em>Update: this isn&#39;t quite right, <a href="#updates">see below</a></em>). If you wanted to make your page load faster, you needed to make your JavaScript bundle smaller. So this is the central goal of the Closure Compiler and its &quot;advanced optimizations&quot; mode.</p>
<p>To see how this works, let&#39;s look at some code to fetch and process data from the network.</p>
Expand Down
2 changes: 1 addition & 1 deletion 2023/10/27/specialize-this/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ <h2>Overload on the type of this to specialize generics (The Lost Item)</h2>
</time>
</div>
<div class="entry-content">
<p><em>I cut one item from <a target="_blank" rel="noopener" href="https://amzn.to/3HIrQN6" onclick="return trackOutboundLink('overload on the type of this to specialize generics the lost item', 'https://amzn.to/3HIrQN6', event);">Effective TypeScript</a> during the final stages of editing. Four years later, it&#39;s time for it to see the light of day! It&#39;s a trick for specializing generic types for certain subtypes of their type parameters. This post shows how it works, why it&#39;s indispensible for wrapper types, and also explains why I cut it from the book.</em></p>
<p><em>I cut one item from <a target="_blank" rel="noopener" href="https://amzn.to/3UjPrsK" onclick="return trackOutboundLink('overload on the type of this to specialize generics the lost item', 'https://amzn.to/3UjPrsK', event);">Effective TypeScript</a> during the final stages of editing. Four years later, it&#39;s time for it to see the light of day! It&#39;s a trick for specializing generic types for certain subtypes of their type parameters. This post shows how it works, why it&#39;s indispensible for wrapper types, and also explains why I cut it from the book.</em></p>
<p>As you write type declarations for generic classes, you may find that you want to make some methods available only for particular values of the generic parameter. This often comes up with wrapper objects. In the lodash utility library, for example, you can rewrite a series of function calls:</p>
<figure class="highlight ts"><table><tr><td class="code"><pre><code class="hljs ts">_.sum(<br> _.map(<br> _.filter(<br> _.split(<span class="hljs-string">&#x27;&#x27;</span> + <span class="hljs-built_in">Math</span>.PI, <span class="hljs-string">&#x27;&#x27;</span>),<br> digit =&gt; digit !== <span class="hljs-string">&#x27;.&#x27;</span>),<br> <span class="hljs-built_in">Number</span>)); <span class="hljs-comment">// result is 80</span><br></code></pre></td></tr></table></figure>

Expand Down
Loading

0 comments on commit 5fc1d54

Please sign in to comment.