urn:uuid:1dd3f532-4b34-4b57-8a23-8abad84ed53dMarius SchulzMarius Schulz on web development, modern JavaScript, and TypeScript.https://mariusschulz.com/images/headshots/marius-schulz-250x250.ycceeztmas.imm.jpghttps://mariusschulz.com/images/headshots/marius-schulz-250x250.ycceeztmas.imm.jpghttps://mariusschulz.com/images/headshots/marius-schulz-250x250.ycceeztmas.imm.jpg2022-06-06T00:00:00.000ZMarius Schulzhttps://mariusschulz.com/marius.schulz@me.comurn:uuid:cc49d6fe-336c-427a-901d-3bbf9ff4d246Keyboard Shortcuts for Jumping and Deleting in iTerm22022-06-05T00:00:00.000Z2022-06-06T00:00:00.000ZHow to configure familiar keyboard shortcuts for common navigation and edit actions in the iTerm2 command prompt, such as jumping to the start or end of a word or line.<p>As a software engineer, I find myself using the terminal every day to run all sorts of commands. My current terminal of choice is <a href="https://iterm2.com/">iTerm2</a> which I’ve been using happily for many years.</p>
<p>Whenever I set up iTerm2 on a new Mac, one of the first things I do is to configure familiar keyboard shortcuts for common navigation and edit actions in the command prompt. For example, I typically configure the <kbd>⌥</kbd><kbd>←</kbd> shortcut which jumps me to the start of the word under the cursor.</p>
<p>To configure custom keyboard shortcuts in iTerm2, open the preferences dialog and navigate to the <em>Profiles › Keys › Key Mappings</em> tab:</p>
<p><img src="/images/content/iterm/iterm_settings_key_mappings-2x.kveu7x6vuz.imm.png" alt="iTerm2 Preferences: Profiles › Keys › Key Mappings" width="2256" height="1394" data-has-image-viewer="true" loading="lazy" decoding="async"></p>
<p>Click the “+” button to add a new key mapping, or double-click an existing key mapping to edit it. For the “Jump to start of word” command, select the “Send Escape Sequence” action and send the escape sequence <code>Esc+b</code>:</p>
<p><img src="/images/content/iterm/iterm_settings_edit_key_mapping-2x.j7eqv3kszn.imm.png" alt="iTerm2 Preferences: dialog for editing a key mapping" width="2256" height="1394" data-has-image-viewer="true" loading="lazy" decoding="async"></p>
<p>Now, whenever you're typing a command in iTerm2, it's really easy to jump back to the start of the word (or even multiple words) to insert more text or delete part of the command — no more need for repeatedly pressing the <kbd>←</kbd> key to navigate back character by character.</p>
<p>Here's the full list of keyboard shortcuts that I configure for various jump and delete commands:</p>
<table>
<thead>
<tr>
<th>Shortcut</th>
<th>Command</th>
<th>Action</th>
<th>Send</th>
</tr>
</thead>
<tbody><tr>
<td><kbd>⌥</kbd><kbd>←</kbd></td>
<td>Jump to start of word</td>
<td>Send Escape Sequence</td>
<td><code>b</code></td>
</tr>
<tr>
<td><kbd>⌥</kbd><kbd>→</kbd></td>
<td>Jump to end of word</td>
<td>Send Escape Sequence</td>
<td><code>f</code></td>
</tr>
<tr>
<td><kbd>⌘</kbd><kbd>←</kbd></td>
<td>Jump to start of line</td>
<td>Send Hex Codes</td>
<td><code>0x01</code></td>
</tr>
<tr>
<td><kbd>⌘</kbd><kbd>→</kbd></td>
<td>Jump to end of line</td>
<td>Send Hex Codes</td>
<td><code>0x05</code></td>
</tr>
<tr>
<td><kbd>⌥</kbd><kbd>⌫</kbd></td>
<td>Delete to start of word</td>
<td>Send Hex Codes</td>
<td><code>0x17</code></td>
</tr>
<tr>
<td><kbd>⌘</kbd><kbd>⌫</kbd></td>
<td>Delete entire line</td>
<td>Send Hex Codes</td>
<td><code>0x15</code></td>
</tr>
</tbody></table>
urn:uuid:6d5e9c03-3be4-4c6b-908f-ff28e983a865Assertion Functions in TypeScript2022-02-13T00:00:00.000Z2022-02-13T00:00:00.000ZTypeScript 3.7 implemented support for assertion functions in the type system. An assertion function is a function that throws an error if something unexpected happened. Using assertion signatures, we can tell TypeScript that a function should be treated as an assertion function.<p>TypeScript 3.7 implemented support for assertion functions in the type system. An assertion function is a function that throws an error if something unexpected happened. Using assertion signatures, we can tell TypeScript that a function should be treated as an assertion function.</p>
<h2 id="an-example-the-document-getelementbyid-method"><a class="heading-anchor" href="#an-example-the-document-getelementbyid-method">#</a>An Example: The <code>document.getElementById()</code> Method</h2>
<p>Let's start by looking at an example in which we're using the <code>document.getElementById()</code> method to find a DOM element that has the ID "root":</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>We're calling the <code>root.addEventListener()</code> method to attach a click handler to the element. However, TypeScript reports a type error:</p>
<pre><code class="language-ts"><div class="line-highlight" style="top: calc((2 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// Object is possibly null</span>
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>The <code>root</code> variable is of type <code>HTMLElement | null</code>, which is why TypeScript reports a type error "Object is possibly null" when we're trying to call the <code>root.addEventListener()</code> method. In order for our code to be considered type-correct, we somehow need to make sure that the <code>root</code> variable is non-null and non-undefined before calling the <code>root.addEventListener()</code> method. We have a couple of options for how we can do that, including:</p>
<ol>
<li>Using the non-null assertion operator <code>!</code></li>
<li>Implementing an inline null check</li>
<li>Implementing an assertion function</li>
</ol>
<p>Let's look at each of the three options.</p>
<h2 id="using-the-non-null-assertion-operator"><a class="heading-anchor" href="#using-the-non-null-assertion-operator">#</a>Using the Non-Null Assertion Operator</h2>
<p>First up, we'll try and use the non-null assertion operator <code>!</code> which is written as a post-fix operator after the <code>document.getElementById()</code> call:</p>
<pre><code class="language-ts"><div class="line-highlight" style="top: calc((0 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">)</span><span style="color:#0184BC">!</span><span style="color:#383A42">;</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>The non-null assertion operator <code>!</code> tells TypeScript to assume that the value returned by <code>document.getElementById()</code> is non-null and non-undefined (also known as “non-nullish”). TypeScript will exclude the types <code>null</code> and <code>undefined</code> from the type of the expression to which we apply the <code>!</code> operator.</p>
<p>In this case, the return type of the <code>document.getElementById()</code> method is <code>HTMLElement | null</code>, so if we apply the <code>!</code> operator, we get <code>HTMLElement</code> as the resulting type. Consequently, TypeScript no longer reports the type error that we saw previously.</p>
<p>However, using the non-null assertion operator is probably not the right fix in this situation. The <code>!</code> operator is completely erased when our TypeScript code is compiled to JavaScript:</p>
<pre><code class="language-js"><div class="line-highlight" style="top: calc((0 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>The non-null assertion operator has no runtime manifestation whatsoever. That is, the TypeScript compiler does not emit any validation code to verify that the expression is actually non-nullish. Therefore, if the <code>document.getElementById()</code> call returns <code>null</code> because no matching element can be found, our <code>root</code> variable will hold the value <code>null</code> and our attempt to call the <code>root.addEventListener()</code> method will fail.</p>
<h2 id="implementing-an-inline-null-check"><a class="heading-anchor" href="#implementing-an-inline-null-check">#</a>Implementing an Inline Null Check</h2>
<p>Let's now consider the second option and implement an inline null check to verify that the <code>root</code> variable holds a non-null value:</p>
<pre><code class="language-ts"><div class="line-highlight" style="top: calc((2 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((3 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((4 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">if</span><span style="color:#383A42"> (root </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> throw</span><span style="color:#4078F2"> Error</span><span style="color:#383A42">(</span><span style="color:#50A14F">"Unable to find DOM element #root"</span><span style="color:#383A42">);</span>
</span><span class="line"><span style="color:#383A42">}</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>Because of our null check, TypeScript's type checker will narrow the type of the <code>root</code> variable from <code>HTMLElement | null</code> (before the null check) to <code>HTMLElement</code> (after the null check):</p>
<pre><code class="language-ts"><div class="line-highlight" style="top: calc((2 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((3 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((9 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((10 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: HTMLElement | null</span>
</span><span class="line"><span style="color:#383A42">root;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">if</span><span style="color:#383A42"> (root </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> throw</span><span style="color:#4078F2"> Error</span><span style="color:#383A42">(</span><span style="color:#50A14F">"Unable to find DOM element #root"</span><span style="color:#383A42">);</span>
</span><span class="line"><span style="color:#383A42">}</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: HTMLElement</span>
</span><span class="line"><span style="color:#383A42">root;</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>This approach is much safer than the previous approach using the non-null assertion operator. We're explicitly handling the case in which the <code>root</code> variable holds the value <code>null</code> by throwing an error with a descriptive error message.</p>
<p>Also, note that this approach does not contain any TypeScript-specific syntax whatsoever; all of the above is syntactically valid JavaScript. TypeScript's <a href="https://mariusschulz.com/blog/control-flow-based-type-analysis-in-typescript">control flow analysis</a> understands the effect of our null check and narrows the type of the <code>root</code> variable in different places of the program — no explicit type annotations needed.</p>
<h2 id="implementing-an-assertion-function"><a class="heading-anchor" href="#implementing-an-assertion-function">#</a>Implementing an Assertion Function</h2>
<p>Lastly, let's now see how we can use an assertion function to implement this null check in a reusable way. We'll start by implementing an <code>assertNonNullish</code> function that will throw an error if the provided value is either <code>null</code> or <code>undefined</code>:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> assertNonNullish</span><span style="color:#383A42">(</span>
</span><span class="line"><span style="color:#383A42"> value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> unknown</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42"> message</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span>
</span><span class="line"><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> if</span><span style="color:#383A42"> (value </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> value </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> throw</span><span style="color:#4078F2"> Error</span><span style="color:#383A42">(message);</span>
</span><span class="line"><span style="color:#383A42"> }</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>We're using the <a href="https://mariusschulz.com/blog/the-unknown-type-in-typescript"><code>unknown</code> type</a> for the <code>value</code> parameter here to allow callsites to pass a value of an arbitrary type. We're only comparing the <code>value</code> parameter to the values <code>null</code> and <code>undefined</code>, so we don't need to require the <code>value</code> parameter to have a more specific type.</p>
<p>Here's how we would use the <code>assertNonNullish</code> function in our example from before. We're passing it the <code>root</code> variable as well as the error message:</p>
<pre><code class="language-ts"><div class="line-highlight" style="top: calc((1 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">);</span>
</span><span class="line"><span style="color:#4078F2">assertNonNullish</span><span style="color:#383A42">(root, </span><span style="color:#50A14F">"Unable to find DOM element #root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>However, TypeScript still produces a type error for the <code>root.addEventListener()</code> method call:</p>
<pre><code class="language-ts"><div class="line-highlight" style="top: calc((3 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">);</span>
</span><span class="line"><span style="color:#4078F2">assertNonNullish</span><span style="color:#383A42">(root, </span><span style="color:#50A14F">"Unable to find DOM element #root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// Object is possibly null</span>
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>If we have a look at the type of the <code>root</code> variable before and after the <code>assertNonNullish()</code> call, we'll see that it is of type <code>HTMLElement | null</code> in both places:</p>
<pre><code class="language-ts"><div class="line-highlight" style="top: calc((2 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((3 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((7 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((8 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: HTMLElement | null</span>
</span><span class="line"><span style="color:#383A42">root;</span>
</span><span class="line">
</span><span class="line"><span style="color:#4078F2">assertNonNullish</span><span style="color:#383A42">(root, </span><span style="color:#50A14F">"Unable to find DOM element #root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: HTMLElement | null</span>
</span><span class="line"><span style="color:#383A42">root;</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>This is because TypeScript doesn't understand that our <code>assertNonNullish</code> function will throw an error if the provided <code>value</code> is nullish. We need to explicitly let TypeScript know that the <code>assertNonNullish</code> function should be treated as an <strong>assertion function</strong> that <em>asserts</em> that the value is non-nullish, and that it will throw an error otherwise. We can do that using the <code>asserts</code> keyword in the return type annotation:</p>
<pre><code class="language-ts"><div class="line-highlight" style="top: calc((0 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((1 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((3 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> assertNonNullish</span><span style="color:#383A42"><</span><span style="color:#C18401">TValue</span><span style="color:#383A42">>(</span>
</span><span class="line"><span style="color:#383A42"> value</span><span style="color:#0184BC">:</span><span style="color:#C18401"> TValue</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42"> message</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span>
</span><span class="line"><span style="color:#383A42">)</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> asserts</span><span style="color:#383A42"> value </span><span style="color:#0184BC">is</span><span style="color:#C18401"> NonNullable</span><span style="color:#383A42"><</span><span style="color:#C18401">TValue</span><span style="color:#383A42">> {</span>
</span><span class="line"><span style="color:#A626A4"> if</span><span style="color:#383A42"> (value </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> value </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> throw</span><span style="color:#4078F2"> Error</span><span style="color:#383A42">(message);</span>
</span><span class="line"><span style="color:#383A42"> }</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>First of all, note that the <code>assertNonNullish</code> function is now a generic function. It declares a single type parameter <code>TValue</code> that we use as the type of the <code>value</code> parameter; we're also using the <code>TValue</code> type in the return type annotation.</p>
<p>The <code>asserts value is NonNullable<TValue></code> return type annotation is what's called an <strong>assertion signature</strong>. This assertion signature says that if the function returns normally (that is, if it doesn't throw an error), it has asserted that the <code>value</code> parameter is of type <code>NonNullable<TValue></code>. TypeScript uses this piece of information to narrow the type of the expression that we passed to the <code>value</code> parameter.</p>
<p>The <code>NonNullable<T></code> type is a <a href="https://mariusschulz.com/blog/conditional-types-in-typescript#the-nonnullable-t-conditional-type">conditional type</a> that is defined in the <em>lib.es5.d.ts</em> type declaration file that ships with the TypeScript compiler:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">/**</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> * Exclude null and undefined from T</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> */</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> NonNullable</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">> </span><span style="color:#0184BC">=</span><span style="color:#C18401"> T</span><span style="color:#A626A4"> extends</span><span style="color:#0184BC"> null</span><span style="color:#0184BC"> |</span><span style="color:#0184BC"> undefined</span><span style="color:#0184BC"> ?</span><span style="color:#0184BC"> never</span><span style="color:#0184BC"> :</span><span style="color:#C18401"> T</span><span style="color:#383A42">;</span></span></code></pre><p>When applied to the type <code>T</code>, the <code>NonNullable<T></code> helper type removes the types <code>null</code> and <code>undefined</code> from <code>T</code>. Here are a few examples:</p>
<ul>
<li><code>NonNullable<HTMLElement></code> evaluates to <code>HTMLElement</code></li>
<li><code>NonNullable<HTMLElement | null></code> evaluates to <code>HTMLElement</code></li>
<li><code>NonNullable<HTMLElement | null | undefined></code> evaluates to <code>HTMLElement</code></li>
<li><code>NonNullable<null></code> evaluates to <code>never</code></li>
<li><code>NonNullable<undefined></code> evaluates to <code>never</code></li>
<li><code>NonNullable<null | undefined></code> evaluates to <code>never</code></li>
</ul>
<p>With our assertion signature in place, TypeScript now correctly narrows the type of the <code>root</code> variable after the <code>assertNonNullish()</code> function call. The type checker understands that when <code>root</code> holds a nullish value, the <code>assertNonNullish</code> function will throw an error. If the control flow of the program makes it past the <code>assertNonNullish()</code> function call, the <code>root</code> variable must contain a non-nullish value, and therefore TypeScript narrows its type accordingly:</p>
<pre><code class="language-ts"><div class="line-highlight" style="top: calc((2 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((3 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((7 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><div class="line-highlight" style="top: calc((8 * var(--pre-line-height)) + var(--pre-padding-vertical));"></div><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: HTMLElement | null</span>
</span><span class="line"><span style="color:#383A42">root;</span>
</span><span class="line">
</span><span class="line"><span style="color:#4078F2">assertNonNullish</span><span style="color:#383A42">(root, </span><span style="color:#50A14F">"Unable to find DOM element #root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: HTMLElement</span>
</span><span class="line"><span style="color:#383A42">root;</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>As a result of this type narrowing, our example now type-checks correctly:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> root</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> document.</span><span style="color:#4078F2">getElementById</span><span style="color:#383A42">(</span><span style="color:#50A14F">"root"</span><span style="color:#383A42">);</span>
</span><span class="line"><span style="color:#4078F2">assertNonNullish</span><span style="color:#383A42">(root, </span><span style="color:#50A14F">"Unable to find DOM element #root"</span><span style="color:#383A42">);</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">root.</span><span style="color:#4078F2">addEventListener</span><span style="color:#383A42">(</span><span style="color:#50A14F">"click"</span><span style="color:#383A42">, e </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> /* ... */</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>So here we have it: a reusable <code>assertNonNullish</code> assertion function that we can use to verify that an expression has a non-nullish value and to narrow the type of that expression accordingly by removing the <code>null</code> and <code>undefined</code> types from it.</p>
urn:uuid:43da542e-0260-4930-aead-36d7209e8c1bOptional Chaining: The ?. Operator in TypeScript2021-08-02T00:00:00.000Z2021-09-11T00:00:00.000ZTypeScript 3.7 added support for the ?. operator, also known as the optional chaining operator. We can use this operator to descend into an object whose properties potentially hold the values null or undefined without writing any null checks for intermediate properties.<p>TypeScript 3.7 added support for the <code>?.</code> operator, also known as the optional chaining operator. We can use optional chaining to descend into an object whose properties potentially hold the values <code>null</code> or <code>undefined</code> without writing any null checks for intermediate properties.</p>
<p>Optional chaining is not a feature specific to TypeScript. The <code>?.</code> operator got added to the ECMAScript standard as part of <a href="https://262.ecma-international.org/11.0/">ES2020</a>. All modern browsers <a href="https://caniuse.com/mdn-javascript_operators_optional_chaining">natively support optional chaining</a> (not including IE11).</p>
<p>In this post, I will go over the following three optional chaining operators and explain why we might want to use them in our TypeScript or JavaScript code:</p>
<ul>
<li><code>?.</code></li>
<li><code>?.[]</code></li>
<li><code>?.()</code></li>
</ul>
<h2 id="motivation"><a class="heading-anchor" href="#motivation">#</a>Motivation</h2>
<p>Let's start by looking at a real-world example in which optional chaining comes in handy. I've defined a <code>serializeJSON</code> function that takes in any value and serializes it as JSON. I'm passing a user object with two properties to the function:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> any</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value);</span>
</span><span class="line"><span style="color:#383A42">}</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> user</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> name</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "Marius Schulz"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> twitter</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "mariusschulz"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">};</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> json</span><span style="color:#0184BC"> =</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(user);</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">console.</span><span style="color:#4078F2">log</span><span style="color:#383A42">(json);</span></span></code></pre><p>The program prints the following output to the console:</p>
<pre><code class="language-json"><span class="line"><span style="color:#383A42">{</span><span style="color:#E45649">"name"</span><span style="color:#383A42">:</span><span style="color:#50A14F">"Marius Schulz"</span><span style="color:#383A42">,</span><span style="color:#E45649">"twitter"</span><span style="color:#383A42">:</span><span style="color:#50A14F">"mariusschulz"</span><span style="color:#383A42">}</span></span></code></pre><p>Now let's say that we want to let callers of our function specify the indentation level. We'll define a <code>SerializationOptions</code> type and add an <code>options</code> parameter to the <code>serializeJSON</code> function. We'll retrieve the indentation level from the <code>options.formatting.indent</code> property:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> formatting</span><span style="color:#0184BC">:</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> indent</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> number</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> };</span>
</span><span class="line"><span style="color:#383A42">};</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> any</span><span style="color:#383A42">, options</span><span style="color:#0184BC">:</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">.</span><span style="color:#E45649">indent</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>We can now specify an indentation level of two spaces when calling <code>serializeJSON</code> like this:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> user</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> name</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "Marius Schulz"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> twitter</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "mariusschulz"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">};</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> json</span><span style="color:#0184BC"> =</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(user, {</span>
</span><span class="line"><span style="color:#E45649"> formatting</span><span style="color:#0184BC">:</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> indent</span><span style="color:#0184BC">:</span><span style="color:#986801"> 2</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42"> },</span>
</span><span class="line"><span style="color:#383A42">});</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">console.</span><span style="color:#4078F2">log</span><span style="color:#383A42">(json);</span></span></code></pre><p>As we would expect, the resulting JSON is now indented with two spaces and broken across multiple lines:</p>
<pre><code class="language-json"><span class="line"><span style="color:#383A42">{</span>
</span><span class="line"><span style="color:#E45649"> "name"</span><span style="color:#383A42">: </span><span style="color:#50A14F">"Marius Schulz"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> "twitter"</span><span style="color:#383A42">: </span><span style="color:#50A14F">"mariusschulz"</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>Typically, <code>options</code> parameters like the one we introduced here are optional. Callers of the function may specify an options object, but they're not required to. Let's adjust our function signature accordingly and make the <code>options</code> parameter optional by appending a question mark to the parameter name:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> any</span><span style="color:#383A42">, options</span><span style="color:#0184BC">?:</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">.</span><span style="color:#E45649">indent</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>Assuming we have the <a href="https://mariusschulz.com/blog/non-nullable-types-in-typescript#strict-null-checking"><code>--strictNullChecks</code> option</a> enabled in our TypeScript project (which is part of the <a href="https://mariusschulz.com/blog/the-strict-compiler-option-in-typescript"><code>--strict</code> family of compiler options</a>), TypeScript should now report the following type error in our <code>options.formatting.indent</code> expression:</p>
<blockquote>
<p>Object is possibly 'undefined'.</p>
</blockquote>
<p>The <code>options</code> parameter is optional, and as a result it might hold the value <code>undefined</code>. We should first check whether <code>options</code> holds the value <code>undefined</code> before accessing <code>options.formatting</code>, otherwise we risk getting an error at runtime:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> any</span><span style="color:#383A42">, options</span><span style="color:#0184BC">?:</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options </span><span style="color:#0184BC">!==</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">.</span><span style="color:#E45649">indent</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#986801"> undefined</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>We could also use a slightly more generic null check instead that will check for both <code>null</code> and <code>undefined</code> — note that we're deliberately using <code>!=</code> instead of <code>!==</code> in this case:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> any</span><span style="color:#383A42">, options</span><span style="color:#0184BC">?:</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options </span><span style="color:#0184BC">!=</span><span style="color:#986801"> null</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">.</span><span style="color:#E45649">indent</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#986801"> undefined</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>Now the type error goes away. We can call the <code>serializeJSON</code> function and pass it an options object with an explicit indentation level:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> json</span><span style="color:#0184BC"> =</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(user, {</span>
</span><span class="line"><span style="color:#E45649"> formatting</span><span style="color:#0184BC">:</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> indent</span><span style="color:#0184BC">:</span><span style="color:#986801"> 2</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42"> },</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>Or we can call it without specifying an options object, in which case the <code>indent</code> variable will hold the value <code>undefined</code> and <code>JSON.stringify</code> will use a default indentation level of zero:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> json</span><span style="color:#0184BC"> =</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(user);</span></span></code></pre><p>Both function calls above are type-correct. However, what if we also wanted to be able to call our <code>serializeJSON</code> function like this?</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> json</span><span style="color:#0184BC"> =</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(user, {});</span></span></code></pre><p>This is another common pattern you'll see. Options objects tend to declare some or all of their properties as optional so that callers of the function can specify as many (or as few) options as needed. We need to make the <code>formatting</code> property in our <code>SerializationOptions</code> type optional in order to support this pattern:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> formatting</span><span style="color:#0184BC">?:</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> indent</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> number</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> };</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>Notice the question mark after the name of the <code>formatting</code> property. Now the <code>serializeJSON(user, {})</code> call is type-correct, but TypeScript reports another type error when accessing <code>options.formatting.indent</code>:</p>
<blockquote>
<p>Object is possibly 'undefined'.</p>
</blockquote>
<p>We'll need to add another null check here given that <code>options.formatting</code> could now hold the value <code>undefined</code>:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> any</span><span style="color:#383A42">, options</span><span style="color:#0184BC">?:</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options </span><span style="color:#0184BC">!=</span><span style="color:#986801"> null</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#0184BC"> !=</span><span style="color:#986801"> null</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">.</span><span style="color:#E45649">indent</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#986801"> undefined</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>This code is now type-correct, and it safely accesses the <code>options.formatting.indent</code> property. These nested null checks are getting pretty unwieldy though, so let's see how we can simplify this property access using the optional chaining operator.</p>
<h2 id="the-operator-dot-notation"><a class="heading-anchor" href="#the-operator-dot-notation">#</a>The <code>?.</code> Operator: Dot Notation</h2>
<p>We can use the <code>?.</code> operator to access <code>options.formatting.indent</code> with checks for nullish values at every level of this property chain:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> any</span><span style="color:#383A42">, options</span><span style="color:#0184BC">?:</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options?.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">?.</span><span style="color:#E45649">indent</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>The <a href="https://tc39.es/ecma262/multipage/">ECMAScript specification</a> describes optional chaining as follows:</p>
<blockquote>
<p>Optional chaining [is] a property access and function invocation operator that short-circuits if the value to access/invoke is nullish.</p>
</blockquote>
<p>The JavaScript runtime evaluates the <code>options?.formatting?.indent</code> expression as follows:</p>
<ul>
<li>If <code>options</code> holds the value <code>null</code> or <code>undefined</code>, produce the value <code>undefined</code>.</li>
<li>Otherwise, if <code>options.formatting</code> holds the value <code>null</code> or <code>undefined</code>, produce the value <code>undefined</code>.</li>
<li>Otherwise, produce the value of <code>options.formatting.indent</code>.</li>
</ul>
<p>Note that the <code>?.</code> operator always produces the value <code>undefined</code> when it stops descending into a property chain, even when it encounters the value <code>null</code>. TypeScript models this behavior in its type system. In the following example, TypeScript infers the <code>indent</code> local variable to be of type <code>number | undefined</code>:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> any</span><span style="color:#383A42">, options</span><span style="color:#0184BC">?:</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options?.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">?.</span><span style="color:#E45649">indent</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>Thanks to optional chaining, this code is a lot more succinct and just as type-safe as before.</p>
<h2 id="the-operator-bracket-notation"><a class="heading-anchor" href="#the-operator-bracket-notation">#</a>The <code>?.[]</code> Operator: Bracket Notation</h2>
<p>Next, let's now look at the <code>?.[]</code> operator, another operator in the optional chaining family.</p>
<p>Let's say that our <code>indent</code> property on the <code>SerializationOptions</code> type was called <code>indent-level</code> instead. We'll need to use quotes to define a property that has a hyphen in its name:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> formatting</span><span style="color:#0184BC">?:</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#50A14F"> "indent-level"</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> number</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> };</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>We could now specify a value for the <code>indent-level</code> property like this when calling the <code>serializeJSON</code> function:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> json</span><span style="color:#0184BC"> =</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(user, {</span>
</span><span class="line"><span style="color:#E45649"> formatting</span><span style="color:#0184BC">:</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#50A14F"> "indent-level"</span><span style="color:#0184BC">:</span><span style="color:#986801"> 2</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42"> },</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>However, the following attempt to access the <code>indent-level</code> property using optional chaining is a syntax error:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options?.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">?.</span><span style="color:#50A14F">"indent-level"</span><span style="color:#383A42">;</span></span></code></pre><p>We cannot use the <code>?.</code> operator directly followed by a string literal — that would be invalid syntax. Instead, we can use the bracket notation of optional chaining and access the <code>indent-level</code> property using the <code>?.[]</code> operator:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options?.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">?.[</span><span style="color:#50A14F">"indent-level"</span><span style="color:#383A42">];</span></span></code></pre><p>Here's our complete <code>serializeJSON</code> function:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> any</span><span style="color:#383A42">, options</span><span style="color:#0184BC">?:</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options?.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">?.[</span><span style="color:#50A14F">"indent-level"</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>It's pretty much the same as before, aside from additional square brackets for the final property access.</p>
<h2 id="the-operator-method-calls"><a class="heading-anchor" href="#the-operator-method-calls">#</a>The <code>?.()</code> Operator: Method Calls</h2>
<p>The third and final operator in the optional chaining family is <code>?.()</code>. We can use the <code>?.()</code> operator to invoke a method which may not exist.</p>
<p>To see when this operator is useful, let's change our <code>SerializationOptions</code> type once again. We'll replace the <code>indent</code> property (typed as a number) by a <code>getIndent</code> property (typed as a parameterless function returning a number):</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> formatting</span><span style="color:#0184BC">?:</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#4078F2"> getIndent</span><span style="color:#0184BC">?:</span><span style="color:#383A42"> () </span><span style="color:#A626A4">=></span><span style="color:#0184BC"> number</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> };</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>We can call our <code>serializeJSON</code> function and specify an indentation level of two as follows:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> json</span><span style="color:#0184BC"> =</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(user, {</span>
</span><span class="line"><span style="color:#E45649"> formatting</span><span style="color:#0184BC">:</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#4078F2"> getIndent</span><span style="color:#0184BC">:</span><span style="color:#383A42"> () </span><span style="color:#A626A4">=></span><span style="color:#986801"> 2</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42"> },</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>To get the indentation level within our <code>serializeJSON</code> function, we can use the <code>?.()</code> operator to conditionally invoke the <code>getIndent</code> method if (and only if) it is defined:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options?.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">?.</span><span style="color:#4078F2">getIndent</span><span style="color:#383A42">?.();</span></span></code></pre><p>If the <code>getIndent</code> method is not defined, no attempt will be made to invoke it. The entire property chain will evaluate to <code>undefined</code> in that case, avoiding the infamous "getIndent is not a function" error.</p>
<p>Here's our complete <code>serializeJSON</code> function once again:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> any</span><span style="color:#383A42">, options</span><span style="color:#0184BC">?:</span><span style="color:#C18401"> SerializationOptions</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> const</span><span style="color:#986801"> indent</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options?.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">?.</span><span style="color:#4078F2">getIndent</span><span style="color:#383A42">?.();</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><h2 id="compiling-optional-chaining-to-older-javascript"><a class="heading-anchor" href="#compiling-optional-chaining-to-older-javascript">#</a>Compiling Optional Chaining to Older JavaScript</h2>
<p>Now that we've seen how the optional chaining operators work and how they're type-checked, let's have a look at the compiled JavaScript which the TypeScript compiler emits when targeting older JavaScript versions.</p>
<p>Here's the JavaScript code that the TypeScript compiler will emit, with whitespace adjusted for readability:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value, options) {</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> _a, _b;</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> indent </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> (_b </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> (_a </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> options </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> options </span><span style="color:#0184BC">===</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">) </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> _a </span><span style="color:#0184BC">===</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> _a.</span><span style="color:#E45649">getIndent</span><span style="color:#383A42">) </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> _b </span><span style="color:#0184BC">===</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> _b.</span><span style="color:#4078F2">call</span><span style="color:#383A42">(_a);</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>There's quite a lot going on in the assignment to the <code>indent</code> variable. Let's simplify the code step by step. We'll start by renaming the local variables <code>_a</code> and <code>_b</code> to <code>formatting</code> and <code>getIndent</code>, respectively:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value, options) {</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> formatting, getIndent;</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> indent </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> (getIndent </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> (formatting </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> options </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> options </span><span style="color:#0184BC">===</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">) </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> formatting </span><span style="color:#0184BC">===</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> formatting.</span><span style="color:#E45649">getIndent</span><span style="color:#383A42">) </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> getIndent </span><span style="color:#0184BC">===</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> getIndent.</span><span style="color:#4078F2">call</span><span style="color:#383A42">(formatting);</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>Next, let's address the <code>void 0</code> expression. The <code>void</code> operator always produces the value <code>undefined</code>, no matter what value it's applied to. We can replace the <code>void 0</code> expression by the value <code>undefined</code> directly:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value, options) {</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> formatting, getIndent;</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> indent </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> (getIndent </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> (formatting </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> options </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> options </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">) </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> formatting </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> formatting.</span><span style="color:#E45649">getIndent</span><span style="color:#383A42">) </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> getIndent </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> getIndent.</span><span style="color:#4078F2">call</span><span style="color:#383A42">(formatting);</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>Next, let's extract the assignment to the <code>formatting</code> variable into a separate statement:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value, options) {</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> formatting </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> options </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> options </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> getIndent;</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> indent </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> (getIndent </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> formatting </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> formatting </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> formatting.</span><span style="color:#E45649">getIndent</span><span style="color:#383A42">) </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> getIndent </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> getIndent.</span><span style="color:#4078F2">call</span><span style="color:#383A42">(formatting);</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>Let's do the same with the assignment to <code>getIndent</code> and add some whitespace:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value, options) {</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> formatting </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> options </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> options </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> getIndent </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> formatting </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> formatting </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> formatting.</span><span style="color:#E45649">getIndent</span><span style="color:#383A42">;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> indent </span><span style="color:#0184BC">=</span>
</span><span class="line"><span style="color:#383A42"> getIndent </span><span style="color:#0184BC">===</span><span style="color:#986801"> null</span><span style="color:#0184BC"> ||</span><span style="color:#383A42"> getIndent </span><span style="color:#0184BC">===</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> getIndent.</span><span style="color:#4078F2">call</span><span style="color:#383A42">(formatting);</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>Lastly, let's combine the checks using <code>===</code> for the values <code>null</code> and <code>undefined</code> into a single check using the <code>==</code> operator. Unless we're dealing with the <a href="https://mariusschulz.com/blog/nullish-coalescing-the-operator-in-typescript/#compiled-output-checking-for-null-and-undefined">special <code>document.all</code> value in our null checks</a>, the two are equivalent:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value, options) {</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> formatting </span><span style="color:#0184BC">=</span><span style="color:#383A42"> options </span><span style="color:#0184BC">==</span><span style="color:#986801"> null</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> options.</span><span style="color:#E45649">formatting</span><span style="color:#383A42">;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> getIndent </span><span style="color:#0184BC">=</span><span style="color:#383A42"> formatting </span><span style="color:#0184BC">==</span><span style="color:#986801"> null</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> formatting.</span><span style="color:#E45649">getIndent</span><span style="color:#383A42">;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> indent </span><span style="color:#0184BC">=</span><span style="color:#383A42"> getIndent </span><span style="color:#0184BC">==</span><span style="color:#986801"> null</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#986801"> undefined</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> getIndent.</span><span style="color:#4078F2">call</span><span style="color:#383A42">(formatting);</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#986801"> JSON</span><span style="color:#383A42">.</span><span style="color:#4078F2">stringify</span><span style="color:#383A42">(value, </span><span style="color:#986801">null</span><span style="color:#383A42">, indent);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>Now the structure of the code is a lot more apparent. You can see that TypeScript is emitting the null checks that we would have written ourselves if we hadn't been able to use the optional chaining operators.</p>
urn:uuid:ecc53675-7a11-4ec1-b4e7-9668f67f60dbHow to Squash the First Two Commits in a Git Repository2020-11-01T00:00:00.000Z2020-11-15T00:00:00.000ZGit 1.7.12 introduced the --root flag for the rebase command that lets you rewrite all the history leading to a specific commit down to the root commit.<p>I recently needed to squash the first two commits in one of my Git repositories. As usual, I ran the <code>git rebase -i</code> command to do an interactive rebase, but I noticed that the root commit didn't appear in the list of commits.</p>
<p>Here's what my Git history looked like:</p>
<pre><code><span class="line"><span>$ git log --graph --oneline</span>
</span><span class="line"><span>* fe2c946 (HEAD -> main) More changes</span>
</span><span class="line"><span>* 2702f8b Small tweaks</span>
</span><span class="line"><span>* ffb98dd Initial commit</span></span></code></pre><p>When I ran <code>git rebase -i ffb98dd</code>, this was the output I got (omitted for brevity):</p>
<pre><code><span class="line"><span>pick 2702f8b Small tweaks</span>
</span><span class="line"><span>pick fe2c946 More changes</span>
</span><span class="line"><span></span>
</span><span class="line"><span># Rebase ffb98dd..fe2c946 onto ffb98dd (2 commands)</span>
</span><span class="line"><span># ...</span></span></code></pre><p>As you can see, the second commmit <code>2702f8b</code> and the third commit <code>fe2c946</code> were listed, but the initial commit <code>ffb98dd</code> wasn't. So how do you squash the second commit into the root commit if the root commit isn't listed?</p>
<p>The solution for this problem was introduced in <a href="https://github.com/git/git/blob/e2850a27a95c6f5b141dd88398b1702d2e524a81/Documentation/RelNotes/1.7.12.txt#L59-L60">Git 1.17.12</a>. We can now specify the <code>--root</code> flag for the <code>rebase</code> command to rebase all reachable commits up to the root:</p>
<pre><code><span class="line"><span>$ git rebase -i --root</span></span></code></pre><p>This allows us to rewrite the Git history down to the root commit. Now, the output includes the root commit <code>ffb98dd</code> in the first line:</p>
<pre><code><span class="line"><span>pick ffb98dd Initial commit</span>
</span><span class="line"><span>pick 2702f8b Small tweaks</span>
</span><span class="line"><span>pick fe2c946 More changes</span>
</span><span class="line"><span></span>
</span><span class="line"><span># Rebase fe2c946 onto 6fafbe0 (3 commands)</span>
</span><span class="line"><span># ...</span></span></code></pre><p>We can use the <code>squash</code> command in the second line to combine <code>ffb98dd</code> and <code>2702f8b</code> into a single commit:</p>
<pre><code><span class="line"><span>pick ffb98dd Initial commit</span>
</span><span class="line"><span>squash 2702f8b Small tweaks</span>
</span><span class="line"><span>pick fe2c946 More changes</span>
</span><span class="line"><span></span>
</span><span class="line"><span># Rebase fe2c946 onto 6fafbe0 (3 commands)</span>
</span><span class="line"><span># ...</span></span></code></pre><p>Now, we need to choose a message for the new combined commit. I kept "Initial commit" since it's still an accurate description. Once the command completes, the Git history looks like this:</p>
<pre><code><span class="line"><span>* bfd9495 (HEAD -> main) More changes</span>
</span><span class="line"><span>* 34901ec Initial commit</span></span></code></pre><p>And there we go! The changes made in the "Small tweaks" commit <code>2702f8b</code> have been folded into our initial commit. Using the <code>--root</code> option with the <code>rebase</code> command, we were able to squash the first two commits into a single one.</p>
urn:uuid:6b7a17fe-9a6b-4749-863d-e21810336d24Nullish Coalescing: The ?? Operator in TypeScript2020-08-06T00:00:00.000Z2021-08-14T00:00:00.000ZTypeScript 3.7 added support for the ?? operator, which is known as the nullish coalescing operator. We can use this operator to provide a fallback value for a value that might be null or undefined.<p>TypeScript 3.7 added support for the <code>??</code> operator, which is known as the <strong>nullish coalescing operator</strong>. We can use this operator to provide a fallback value for a value that might be <code>null</code> or <code>undefined</code>.</p>
<h2 id="truthy-and-falsy-values-in-javascript"><a class="heading-anchor" href="#truthy-and-falsy-values-in-javascript">#</a>Truthy and Falsy Values in JavaScript</h2>
<p>Before we dive into the <code>??</code> operator, let's recall that JavaScript values can either be <a href="https://developer.mozilla.org/en-US/docs/Glossary/Truthy">truthy</a> or <a href="https://developer.mozilla.org/en-US/docs/Glossary/Falsy">falsy</a>: when coerced to a Boolean, a value can either produce the value <code>true</code> or <code>false</code>. In JavaScript, the following values are considered to be falsy:</p>
<ul>
<li><code>false</code></li>
<li><code>0</code></li>
<li><code>-0</code></li>
<li><code>0n</code></li>
<li><code>NaN</code></li>
<li><code>""</code></li>
<li><code>null</code></li>
<li><code>undefined</code></li>
</ul>
<p>All other JavaScript values will produce the value <code>true</code> when coerced to a Boolean and are thus considered truthy.</p>
<h2 id="providing-fallback-values-with-the-operator"><a class="heading-anchor" href="#providing-fallback-values-with-the-operator">#</a>Providing Fallback Values with the <code>??</code> Operator</h2>
<p>The <code>??</code> operator can be used to provide a fallback value in case another value is <code>null</code> or <code>undefined</code>. It takes two operands and is written like this:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#383A42">value </span><span style="color:#0184BC">??</span><span style="color:#383A42"> fallbackValue;</span></span></code></pre><p>If the left operand is <code>null</code> or <code>undefined</code>, the <code>??</code> expression evaluates to the right operand:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#986801">null</span><span style="color:#0184BC"> ??</span><span style="color:#50A14F"> "n/a"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// "n/a"</span>
</span><span class="line">
</span><span class="line"><span style="color:#986801">undefined</span><span style="color:#0184BC"> ??</span><span style="color:#50A14F"> "n/a"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// "n/a"</span></span></code></pre><p>Otherwise, the <code>??</code> expression evaluates to the left operand:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#986801">false</span><span style="color:#0184BC"> ??</span><span style="color:#986801"> true</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// false</span>
</span><span class="line">
</span><span class="line"><span style="color:#986801">0</span><span style="color:#0184BC"> ??</span><span style="color:#986801"> 100</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// 0</span>
</span><span class="line">
</span><span class="line"><span style="color:#50A14F">""</span><span style="color:#0184BC"> ??</span><span style="color:#50A14F"> "n/a"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// ""</span>
</span><span class="line">
</span><span class="line"><span style="color:#986801">NaN</span><span style="color:#0184BC"> ??</span><span style="color:#986801"> 0</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// NaN</span></span></code></pre><p>Notice that all left operands above are falsy values. If we had used <a href="/blog/the-and-and-or-operators-in-javascript">the <code>||</code> operator</a> instead of the <code>??</code> operator, all of these expressions would've evaluated to their respective right operands:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#986801">false</span><span style="color:#0184BC"> ||</span><span style="color:#986801"> true</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// true</span>
</span><span class="line">
</span><span class="line"><span style="color:#986801">0</span><span style="color:#0184BC"> ||</span><span style="color:#986801"> 100</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// 100</span>
</span><span class="line">
</span><span class="line"><span style="color:#50A14F">""</span><span style="color:#0184BC"> ||</span><span style="color:#50A14F"> "n/a"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// "n/a"</span>
</span><span class="line">
</span><span class="line"><span style="color:#986801">NaN</span><span style="color:#0184BC"> ||</span><span style="color:#986801"> 0</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// 0</span></span></code></pre><p>This behavior is why you shouldn't use the <code>||</code> operator to provide a fallback value for a nullable value. For falsy values, the result might not be the one you wanted or expected. Consider this example:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> Options</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> prettyPrint</span><span style="color:#0184BC">?:</span><span style="color:#0184BC"> boolean</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">};</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> serializeJSON</span><span style="color:#383A42">(value</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> unknown</span><span style="color:#383A42">, options</span><span style="color:#0184BC">:</span><span style="color:#C18401"> Options</span><span style="color:#383A42">)</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A626A4"> const</span><span style="color:#986801"> prettyPrint</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> options.</span><span style="color:#E45649">prettyPrint</span><span style="color:#0184BC"> ??</span><span style="color:#986801"> true</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> // ...</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>The expression <code>options.prettyPrint ?? true</code> lets us provide the default value <code>true</code> in case that the <code>prettyPrint</code> property contains the value <code>null</code> or <code>undefined</code>. If <code>prettyPrint</code> contains the value <code>false</code>, the expression <code>false ?? true</code> still evaluates to <code>false</code>, which is exactly the behavior we want here.</p>
<p>Note that using the <code>||</code> operator here would lead to incorrect results. <code>options.prettyPrint || true</code> would evaluate to <code>true</code> for the values <code>null</code> and <code>undefined</code>, but also for the value <code>false</code>. This would clearly not be intended. I've seen this happen in practice a handful of times, so make sure to keep this case in mind and use towards the <code>??</code> operator instead.</p>
<h2 id="compiled-output-es2020-and-newer"><a class="heading-anchor" href="#compiled-output-es2020-and-newer">#</a>Compiled Output: ES2020 and Newer</h2>
<p>The nullish coalescing operator has reached Stage 4 ("Finished") of <a href="https://tc39.es/process-document/">the TC39 process</a> and is now <a href="https://github.com/tc39/proposals/blob/master/finished-proposals.md">officially part of ES2020</a>. Therefore, the TypeScript compiler will emit the <code>??</code> operator as is without any downleveling when you're targeting <code>"ES2020"</code> (or a newer language version) or <code>"ESNext"</code> in your <em>tsconfig.json</em> file:</p>
<pre><code class="language-json"><span class="line"><span style="color:#383A42">{</span>
</span><span class="line"><span style="color:#E45649"> "compilerOptions"</span><span style="color:#383A42">: {</span>
</span><span class="line"><span style="color:#E45649"> "strict"</span><span style="color:#383A42">: </span><span style="color:#0184BC">true</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> "target"</span><span style="color:#383A42">: </span><span style="color:#50A14F">"ES2020"</span>
</span><span class="line"><span style="color:#383A42"> }</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>So, this simple expression will be emitted unchanged:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#383A42">value </span><span style="color:#0184BC">??</span><span style="color:#383A42"> fallbackValue;</span></span></code></pre><p>If you're planning on using the <code>??</code> operator while targeting <code>"ES2020"</code> or a newer language version, head over to <a href="https://caniuse.com/#feat=mdn-javascript_operators_nullish_coalescing">caniuse.com</a> and <a href="https://node.green/#ES2020-features--nullish-coalescing-operator-----">node.green</a> and make sure that all the JavaScript engines you need to support have implemented the operator.</p>
<h2 id="compiled-javascript-output-es2019-and-older"><a class="heading-anchor" href="#compiled-javascript-output-es2019-and-older">#</a>Compiled JavaScript Output: ES2019 and Older</h2>
<p>If you're targeting <code>"ES2019"</code> or an older language version in your <em>tsconfig.json</em> file, the TypeScript compiler will rewrite the nullish coalescing operator into a conditional expression. That way, we can start using the <code>??</code> operator in our code today and still have the compiled code successfully parse and execute in older JavaScript engines.</p>
<p>Let's look at the same simple <code>??</code> expression again:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#383A42">value </span><span style="color:#0184BC">??</span><span style="color:#383A42"> fallbackValue;</span></span></code></pre><p>Assuming we're targeting <code>"ES2019"</code> or a lower language version, the TypeScript compiler will emit the following JavaScript code:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">value </span><span style="color:#0184BC">!==</span><span style="color:#986801"> null</span><span style="color:#0184BC"> &&</span><span style="color:#383A42"> value </span><span style="color:#0184BC">!==</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span><span style="color:#0184BC"> ?</span><span style="color:#383A42"> value </span><span style="color:#0184BC">:</span><span style="color:#383A42"> fallbackValue;</span></span></code></pre><p>The <code>value</code> variable is compared against both <code>null</code> and <code>undefined</code> (the result of the expression <code>void 0</code>). If both comparisons produce the value <code>false</code>, the entire expression evaluates to <code>value</code>; otherwise, it evaluates to <code>fallbackValue</code>.</p>
<p>Now, let's look at a slightly more complex example. Instead of a simple <code>value</code> variable, we're going to use a <code>getValue()</code> call expression as the left operand of the <code>??</code> operator:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> value</span><span style="color:#0184BC"> =</span><span style="color:#4078F2"> getValue</span><span style="color:#383A42">() </span><span style="color:#0184BC">??</span><span style="color:#383A42"> fallbackValue;</span></span></code></pre><p>In this case, the compiler will emit the following JavaScript code (modulo whitespace differences):</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">var</span><span style="color:#383A42"> _a;</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> value</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> (_a </span><span style="color:#0184BC">=</span><span style="color:#4078F2"> getValue</span><span style="color:#383A42">()) </span><span style="color:#0184BC">!==</span><span style="color:#986801"> null</span><span style="color:#0184BC"> &&</span><span style="color:#383A42"> _a </span><span style="color:#0184BC">!==</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span>
</span><span class="line"><span style="color:#0184BC"> ?</span><span style="color:#383A42"> _a</span>
</span><span class="line"><span style="color:#0184BC"> :</span><span style="color:#383A42"> fallbackValue;</span></span></code></pre><p>You can see that the compiler generated an intermediate variable <code>_a</code> to store the return value of the <code>getValue()</code> call. The <code>_a</code> variable is then compared against <code>null</code> and <code>void 0</code> and (potentially) used as the resulting value of the entire expression. This intermediate variable is necessary so that the <code>getValue</code> function is only called once.</p>
<h2 id="compiled-output-checking-for-null-and-undefined"><a class="heading-anchor" href="#compiled-output-checking-for-null-and-undefined">#</a>Compiled Output: Checking for <code>null</code> and <code>undefined</code></h2>
<p>You might be wondering why the compiler emits the following expression to check the <code>value</code> variable against <code>null</code> and <code>undefined</code>:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">value </span><span style="color:#0184BC">!==</span><span style="color:#986801"> null</span><span style="color:#0184BC"> &&</span><span style="color:#383A42"> value </span><span style="color:#0184BC">!==</span><span style="color:#0184BC"> void</span><span style="color:#986801"> 0</span><span style="color:#383A42">;</span></span></code></pre><p>Couldn't the compiler emit the following shorter check instead?</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">value </span><span style="color:#0184BC">!=</span><span style="color:#986801"> null</span><span style="color:#383A42">;</span></span></code></pre><p>Unfortunately, it can't do that without sacrificing correctness. For almost all values in JavaScript, the comparison <code>value == null</code> is equivalent to <code>value === null || value === undefined</code>. For those values, the negation <code>value != null</code> is equivalent to <code>value !== null && value !== undefined</code>. However, there is one value for which these two checks aren't equivalent, and that value is <code>document.all</code>:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">document.</span><span style="color:#E45649">all</span><span style="color:#0184BC"> ===</span><span style="color:#986801"> null</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// false</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">document.</span><span style="color:#E45649">all</span><span style="color:#0184BC"> ===</span><span style="color:#986801"> undefined</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// false</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">document.</span><span style="color:#E45649">all</span><span style="color:#0184BC"> ==</span><span style="color:#986801"> null</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// true</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">document.</span><span style="color:#E45649">all</span><span style="color:#0184BC"> ==</span><span style="color:#986801"> undefined</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// true</span></span></code></pre><p>The value <code>document.all</code> is not considered to be strictly equal to either <code>null</code> or <code>undefined</code>, but it is considered to be loosely equal to both <code>null</code> and <code>undefined</code>. Because of this anomaly, the TypeScript compiler can't emit <code>value != null</code> as a check because it would produce incorrect results for <code>document.all</code>.</p>
<p>You can read more about this curious behavior in an answer to the <a href="https://stackoverflow.com/a/10394873/362634">Why is document.all falsy?</a> question on Stack Overflow. Oh, the things we do for web compatibility.</p>
urn:uuid:94d82e13-cdfe-4efe-ab22-20c6fbeef566Declaring Global Variables in TypeScript2020-04-14T00:00:00.000Z2020-04-16T00:00:00.000ZDifferent approaches for declaring a global variable in TypeScript.<p>Every now and then, you might want to statically type a global variable in TypeScript. For example, in some of my web applications, I need to pass a few properties from my markup rendered on the server to my JavaScript code running in the browser. To do that, I typically define a global variable named <code>__INITIAL_DATA__</code> within an inline script and assign to it a JSON-serialized object:</p>
<pre><code class="language-html"><span class="line"><span style="color:#383A42"><</span><span style="color:#E45649">script</span><span style="color:#383A42">></span>
</span><span class="line"><span style="color:#383A42"> window.</span><span style="color:#E45649">__INITIAL_DATA__</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> userID</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "536891193569405430"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42"> };</span>
</span><span class="line"><span style="color:#383A42"></</span><span style="color:#E45649">script</span><span style="color:#383A42">></span></span></code></pre><p>Now, if I try to access <code>window.__INITIAL_DATA__</code> in a TypeScript file, the compiler will produce a type error because it can't find a definition of the <code>__INITIAL_DATA__</code> property anywhere:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Property '__INITIAL_DATA__' does not exist</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// on type 'Window & typeof globalThis'</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> initialData</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> window.</span><span style="color:#E45649">__INITIAL_DATA__</span><span style="color:#383A42">;</span></span></code></pre><p>I'm going to show you a few different approaches for letting TypeScript know about the <code>window.__INITIAL_DATA__</code> property and making the type error go away.</p>
<h2 id="using-a-type-assertion"><a class="heading-anchor" href="#using-a-type-assertion">#</a>Using a Type Assertion</h2>
<p>The quickest way to make the type error go away is to use the <code>any</code> type in a type assertion. We can treat the <code>window</code> object to be of type <code>any</code> so that we can access its <code>__INITIAL_DATA__</code> property:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> initialData</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> (window as </span><span style="color:#0184BC">any</span><span style="color:#383A42">).</span><span style="color:#E45649">__INITIAL_DATA__</span><span style="color:#383A42">;</span></span></code></pre><p>This solution works, and we longer get a type error. This is a pragmatic approach if you need an ad-hoc way to access a property on the <code>window</code> object that TypeScript doesn't know about.</p>
<p>The <code>(window as any).__INITIAL_DATA__</code> expression is of type <code>any</code>, and therefore <code>initialData</code> is of type <code>any</code> too. We could go one step further and use another type assertion to give the <code>initialData</code> variable a more specific type:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> InitialData</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> userID</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">};</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> initialData</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> (window as </span><span style="color:#0184BC">any</span><span style="color:#383A42">).</span><span style="color:#E45649">__INITIAL_DATA__</span><span style="color:#383A42"> as </span><span style="color:#C18401">InitialData</span><span style="color:#383A42">;</span></span></code></pre><p>Now, we can access <code>initialData.userID</code> in a type-safe way:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> userID</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> initialData.</span><span style="color:#E45649">userID</span><span style="color:#383A42">; </span><span style="color:#A0A1A7;font-style:italic">// Type string</span></span></code></pre><p>Do keep in mind that this is not a guarantee that <code>window.__INITIAL_DATA__</code> will be set correctly at runtime. The type checker trusts us and it is our job to make sure that we assign an object with the expected shape to <code>window.__INITIAL_DATA__</code>.</p>
<h2 id="declare-a-global-variable"><a class="heading-anchor" href="#declare-a-global-variable">#</a>Declare a Global Variable</h2>
<p>Another approach is to declare a global variable using the <code>declare var</code> syntax. This way, we can let TypeScript know that it can expect to find a global variable with the given name and type:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">declare</span><span style="color:#A626A4"> var</span><span style="color:#383A42"> __INITIAL_DATA__</span><span style="color:#0184BC">:</span><span style="color:#C18401"> InitialData</span><span style="color:#383A42">;</span></span></code></pre><p>We can now access the <code>__INITIAL_DATA__</code> variable directly …</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> initialData</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> __INITIAL_DATA__;</span></span></code></pre><p>… or off of the <code>window</code> object:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> initialData</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> window.</span><span style="color:#E45649">__INITIAL_DATA__</span><span style="color:#383A42">;</span></span></code></pre><p>Note that the access via <code>window.__INITIAL_DATA__</code> will not work from within an <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules">ECMAScript module</a>. If your JavaScript file contains top-level <code>import</code> or <code>export</code> declarations, it is considered a module, and you will receive a type error if you try to access the <code>__INITIAL_DATA__</code> on the <code>window</code> object.</p>
<p>You can declare a global variable in the global scope by using the <code>declare global { ... }</code> syntax to be able to access both <code>window.__INITIAL_DATA__</code> as well as <code>__INITIAL_DATA__</code> directly within a JavaScript module.:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">export</span><span style="color:#A626A4"> function</span><span style="color:#4078F2"> someExportedFunction</span><span style="color:#383A42">() {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> // ...</span>
</span><span class="line"><span style="color:#383A42">}</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">declare</span><span style="color:#383A42"> global {</span>
</span><span class="line"><span style="color:#A626A4"> var</span><span style="color:#383A42"> __INITIAL_DATA__</span><span style="color:#0184BC">:</span><span style="color:#C18401"> InitialData</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">}</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> initialData</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> window.</span><span style="color:#E45649">__INITIAL_DATA__</span><span style="color:#383A42">;</span></span></code></pre><p>If you need to access <code>window.__INITIAL_DATA__</code> in several files or modules, it might be a good idea to create a <em>globals.d.ts</em> file in your project. In that file, you can declare all global variables you'll use:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">declare</span><span style="color:#A626A4"> var</span><span style="color:#383A42"> __INITIAL_DATA__</span><span style="color:#0184BC">:</span><span style="color:#C18401"> InitialData</span><span style="color:#383A42">;</span></span></code></pre><p>As long as <em>globals.d.ts</em> is part of your TypeScript project, the compiler will know that <code>__INITIAL_DATA__</code> is a global variable, and it will let you access it via both <code>__INITIAL_DATA__</code> as well as <code>window.__INITIAL_DATA__</code>.</p>
<h2 id="augmenting-the-window-interface"><a class="heading-anchor" href="#augmenting-the-window-interface">#</a>Augmenting the Window Interface</h2>
<p>Lastly, you can use TypeScript's <a href="https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces">interface declaration merging</a> to let the compiler know that it can expect to find a property named <code>__INITIAL_DATA__</code> on the <code>Window</code> type and therefore the <code>window</code> object. To do that, you'll need to define an interface named <code>Window</code> with a property named <code>__INITIAL_DATA__</code>:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">interface</span><span style="color:#C18401"> Window</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> __INITIAL_DATA__</span><span style="color:#0184BC">:</span><span style="color:#C18401"> InitialData</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>TypeScript will merge this interface definition together with the <code>Window</code> interface defined in <em>lib.dom.d.ts</em>, resulting in a single <code>Window</code> type. Now, the following assignment will no longer produce a type error:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> initialData</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> window.</span><span style="color:#E45649">__INITIAL_DATA__</span><span style="color:#383A42">;</span></span></code></pre><p>Note that once again, this approach will not work within a JavaScript module. You'll need to use the <code>declare global { ... }</code> syntax again in order for the <code>window.__INITIAL_DATA__</code> expression to type-check correctly:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">export</span><span style="color:#A626A4"> function</span><span style="color:#4078F2"> someExportedFunction</span><span style="color:#383A42">() {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> // ...</span>
</span><span class="line"><span style="color:#383A42">}</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">declare</span><span style="color:#383A42"> global {</span>
</span><span class="line"><span style="color:#A626A4"> interface</span><span style="color:#C18401"> Window</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> __INITIAL_DATA__</span><span style="color:#0184BC">:</span><span style="color:#C18401"> InitialData</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> }</span>
</span><span class="line"><span style="color:#383A42">}</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> initialData</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> window.</span><span style="color:#E45649">__INITIAL_DATA__</span><span style="color:#383A42">;</span></span></code></pre>urn:uuid:e3c28813-f8e0-4f3b-a6a5-41251f66f984Concatenating Arrays in JavaScript2020-03-31T00:00:00.000Z2021-05-01T00:00:00.000ZIn JavaScript, there are different approaches to concatenating multiple arrays into a single one. A comparison of push(), concat(), and spread syntax.<p>It's a common task to concatenate multiple arrays into a single one. In JavaScript, there are several different approaches we can take. Some of them mutate the target array; others leave all input arrays unchanged and return a new array instead.</p>
<p>In this post, I want to compare the following common approaches:</p>
<ul>
<li>Appending elements to an existing array with <code>Array.prototype.push()</code></li>
<li>Appending elements to a new array with <code>Array.prototype.push()</code></li>
<li>Concatenating multiple arrays with <code>Array.prototype.concat()</code></li>
<li>Using spread syntax in an array literal</li>
</ul>
<p>Let's take a look.</p>
<h2 id="appending-elements-to-an-existing-array-with-array-prototype-push"><a class="heading-anchor" href="#appending-elements-to-an-existing-array-with-array-prototype-push">#</a>Appending Elements to an Existing Array with <code>Array.prototype.push()</code></h2>
<p>First up, the good old <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push"><code>Array.prototype.push()</code></a> method. Let's assume we have the following two arrays:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array1</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">1</span><span style="color:#383A42">, </span><span style="color:#986801">2</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array2</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">4</span><span style="color:#383A42">, </span><span style="color:#986801">5</span><span style="color:#383A42">, </span><span style="color:#986801">6</span><span style="color:#383A42">];</span></span></code></pre><p>We can append all elements of <code>array2</code> to <code>array1</code> by looping over <code>array2</code> and calling <code>array1.push()</code> repeatedly:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">for</span><span style="color:#383A42"> (</span><span style="color:#A626A4">const</span><span style="color:#986801"> element</span><span style="color:#A626A4"> of</span><span style="color:#383A42"> array2) {</span>
</span><span class="line"><span style="color:#383A42"> array1.</span><span style="color:#4078F2">push</span><span style="color:#383A42">(element);</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>Once that code has run, <code>array1</code> now contains all six values; it has been modified in place. <code>array2</code>, on the other hand, remains unchanged:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">array1; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3, 4, 5, 6]</span>
</span><span class="line"><span style="color:#383A42">array2; </span><span style="color:#A0A1A7;font-style:italic">// [4, 5, 6]</span></span></code></pre><p>Instead of the <code>for...of</code> loop, we could've passed all elements of <code>array2</code> as arguments to the <code>push()</code> method call using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax">spread syntax</a>:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">array1.</span><span style="color:#4078F2">push</span><span style="color:#383A42">(</span><span style="color:#0184BC">...</span><span style="color:#383A42">array2);</span></span></code></pre><p>This is equivalent to the following method call:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">array1.</span><span style="color:#4078F2">push</span><span style="color:#383A42">(</span><span style="color:#986801">4</span><span style="color:#383A42">, </span><span style="color:#986801">5</span><span style="color:#383A42">, </span><span style="color:#986801">6</span><span style="color:#383A42">);</span></span></code></pre><p>The result is the same in all cases. <code>array1</code> now contains all six values, <code>array2</code> remains unchanged:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">array1; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3, 4, 5, 6]</span>
</span><span class="line"><span style="color:#383A42">array2; </span><span style="color:#A0A1A7;font-style:italic">// [4, 5, 6]</span></span></code></pre><p>Sometimes, mutating the target array might not be the desired behavior. This is particularly important when you're writing your code in a functional style, composing <a href="https://en.wikipedia.org/wiki/Pure_function">pure functions</a> that don't have side effects. Those functions should not modify any of their parameters; you therefore shouldn't call the <code>push()</code> method on an array that was passed to the function as a parameter.</p>
<h2 id="appending-elements-to-a-new-array-with-array-prototype-push"><a class="heading-anchor" href="#appending-elements-to-a-new-array-with-array-prototype-push">#</a>Appending Elements to a New Array with <code>Array.prototype.push()</code></h2>
<p>Let's take a look at an approach that uses the <code>push()</code> method without mutating any of the arrays that we want to concatenate. Here are our two input arrays again:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array1</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">1</span><span style="color:#383A42">, </span><span style="color:#986801">2</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array2</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">4</span><span style="color:#383A42">, </span><span style="color:#986801">5</span><span style="color:#383A42">, </span><span style="color:#986801">6</span><span style="color:#383A42">];</span></span></code></pre><p>Instead of appending the elements of <code>array2</code> to <code>array1</code>, we can create a new empty array and push the elements of both <code>array1</code> and <code>array2</code> into that:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> concatenated</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [];</span>
</span><span class="line"><span style="color:#383A42">concatenated.</span><span style="color:#4078F2">push</span><span style="color:#383A42">(</span><span style="color:#0184BC">...</span><span style="color:#383A42">array1);</span>
</span><span class="line"><span style="color:#383A42">concatenated.</span><span style="color:#4078F2">push</span><span style="color:#383A42">(</span><span style="color:#0184BC">...</span><span style="color:#383A42">array2);</span></span></code></pre><p>Here's what the three arrays look like after the above code has finished executing:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">array1; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3]</span>
</span><span class="line"><span style="color:#383A42">array2; </span><span style="color:#A0A1A7;font-style:italic">// [4, 5, 6]</span>
</span><span class="line"><span style="color:#383A42">concatenated; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3, 4, 5, 6]</span></span></code></pre><p>The <code>push()</code> is still a mutating method, but in this case, it only mutated <code>concatenated</code>, leaving <code>array1</code> and <code>array2</code> unchanged. This approach is fine even within a pure function that takes <code>array1</code> and <code>array2</code> as parameters. As long as the function is returning the same value when given the same parameters and it doesn't have any side effects (such as modifying its parameters), it is still considered a pure function, even if we locally use mutation within the function body.</p>
<h2 id="concatenating-multiple-arrays-with-array-prototype-concat"><a class="heading-anchor" href="#concatenating-multiple-arrays-with-array-prototype-concat">#</a>Concatenating Multiple Arrays with <code>Array.prototype.concat()</code></h2>
<p>Now that we've seen how to work with the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push"><code>Array.prototype.push()</code></a> method, which mutates the target array, let's take a look at <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat"><code>Array.prototype.concat()</code></a>, a non-mutating method. We'll start out with the same two arrays again:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array1</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">1</span><span style="color:#383A42">, </span><span style="color:#986801">2</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array2</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">4</span><span style="color:#383A42">, </span><span style="color:#986801">5</span><span style="color:#383A42">, </span><span style="color:#986801">6</span><span style="color:#383A42">];</span></span></code></pre><p>We'll then call the <code>concat()</code> method on <code>array1</code>, passing <code>array2</code> as a parameter:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> concatenated</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> array1.</span><span style="color:#4078F2">concat</span><span style="color:#383A42">(array2);</span></span></code></pre><p>Since the <code>concat()</code> method is non-mutating, it neither modifies <code>array1</code> nor <code>array2</code>. Instead, it returns a new array that contains all elements of <code>array1</code> and <code>array2</code> concatenated together:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">array1; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3]</span>
</span><span class="line"><span style="color:#383A42">array2; </span><span style="color:#A0A1A7;font-style:italic">// [4, 5, 6]</span>
</span><span class="line"><span style="color:#383A42">concatenated; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3, 4, 5, 6]</span></span></code></pre><p>Just like the <code>push()</code> method, the <code>concat()</code> method accepts arbitrarily many arguments. That's useful if you want to concatenate three or more arrays together:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array1</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">1</span><span style="color:#383A42">, </span><span style="color:#986801">2</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array2</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">4</span><span style="color:#383A42">, </span><span style="color:#986801">5</span><span style="color:#383A42">, </span><span style="color:#986801">6</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array3</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">7</span><span style="color:#383A42">, </span><span style="color:#986801">8</span><span style="color:#383A42">, </span><span style="color:#986801">9</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> concatenated</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> array1.</span><span style="color:#4078F2">concat</span><span style="color:#383A42">(array2, array3);</span></span></code></pre><p>And just like before, all input arrays remain unchanged:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">array1; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3]</span>
</span><span class="line"><span style="color:#383A42">array2; </span><span style="color:#A0A1A7;font-style:italic">// [4, 5, 6]</span>
</span><span class="line"><span style="color:#383A42">array3; </span><span style="color:#A0A1A7;font-style:italic">// [7, 8, 9]</span>
</span><span class="line"><span style="color:#383A42">concatenated; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3, 4, 5, 6, 7, 8, 9]</span></span></code></pre><p>Sometimes, you might not know upfront how many arrays you want to concatenate. Let's say we have an array of arrays that we want to concatenate into a single one:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array1</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">1</span><span style="color:#383A42">, </span><span style="color:#986801">2</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array2</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">4</span><span style="color:#383A42">, </span><span style="color:#986801">5</span><span style="color:#383A42">, </span><span style="color:#986801">6</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array3</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">7</span><span style="color:#383A42">, </span><span style="color:#986801">8</span><span style="color:#383A42">, </span><span style="color:#986801">9</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> arrays</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [array1, array2, array3];</span></span></code></pre><p>Using spread syntax again, we can spread all elements of <code>arrays</code> as arguments into the <code>concat()</code> method call:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> concatenated</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [].</span><span style="color:#4078F2">concat</span><span style="color:#383A42">(</span><span style="color:#0184BC">...</span><span style="color:#383A42">arrays);</span></span></code></pre><p>Notice that we're creating an empty array here so that we can call the <code>concat()</code> method on it. Since it doesn't contain any elements, the empty array doesn't change the resulting concatenated array. And as before, all input arrays remain unchanged:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">array1; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3]</span>
</span><span class="line"><span style="color:#383A42">array2; </span><span style="color:#A0A1A7;font-style:italic">// [4, 5, 6]</span>
</span><span class="line"><span style="color:#383A42">array3; </span><span style="color:#A0A1A7;font-style:italic">// [7, 8, 9]</span>
</span><span class="line"><span style="color:#383A42">arrays; </span><span style="color:#A0A1A7;font-style:italic">// [[1, 2, 3], [4, 5, 6], [7, 8, 9]]</span>
</span><span class="line"><span style="color:#383A42">concatenated; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3, 4, 5, 6, 7, 8, 9]</span></span></code></pre><p>Note that the <code>concat()</code> method doesn't recursively flatten arrays. It concatenates all elements in all of its arrays without unwrapping nested arrays:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array1</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">1</span><span style="color:#383A42">, [</span><span style="color:#986801">2</span><span style="color:#383A42">], </span><span style="color:#986801">3</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array2</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">4</span><span style="color:#383A42">, [</span><span style="color:#986801">5</span><span style="color:#383A42">, [</span><span style="color:#986801">6</span><span style="color:#383A42">]]];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> concatenated</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> array1.</span><span style="color:#4078F2">concat</span><span style="color:#383A42">(array2);</span></span></code></pre><p>The resulting <code>concatenated</code> array contains the three elements of <code>array1</code>, followed by the two elements of <code>array2</code>, totaling five elements:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">concatenated; </span><span style="color:#A0A1A7;font-style:italic">// [1, [2], 3, 4, [5, [6]]]</span>
</span><span class="line"><span style="color:#383A42">concatenated.</span><span style="color:#E45649">length</span><span style="color:#383A42">; </span><span style="color:#A0A1A7;font-style:italic">// 5</span></span></code></pre><h2 id="using-spread-syntax-in-an-array-literal"><a class="heading-anchor" href="#using-spread-syntax-in-an-array-literal">#</a>Using Spread Syntax in an Array Literal</h2>
<p>Lastly, let's look at <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_array_literals">spread syntax in array literals</a>. Just like before, we'll assume we have two input arrays that we want to concatenate:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array1</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">1</span><span style="color:#383A42">, </span><span style="color:#986801">2</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array2</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">4</span><span style="color:#383A42">, </span><span style="color:#986801">5</span><span style="color:#383A42">, </span><span style="color:#986801">6</span><span style="color:#383A42">];</span></span></code></pre><p>Using spread syntax in an array literal, we can create a new array that contains all elements of <code>array1</code>, followed by all elements of <code>array2</code>:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> concatenated</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#0184BC">...</span><span style="color:#383A42">array1, </span><span style="color:#0184BC">...</span><span style="color:#383A42">array2];</span></span></code></pre><p>And once again, we can see that neither <code>array1</code> nor <code>array2</code> has been modified:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">array1; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3]</span>
</span><span class="line"><span style="color:#383A42">array2; </span><span style="color:#A0A1A7;font-style:italic">// [4, 5, 6]</span>
</span><span class="line"><span style="color:#383A42">concatenated; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3, 4, 5, 6]</span></span></code></pre><p>The great thing about spread syntax is that it invokes the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols">iteration protocol</a> of the element that we're spreading. This means that spreading works with any iterable, rather than only with arrays. For example, we could spread all values in a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set"><code>Set</code></a> into a new array:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> uniques</span><span style="color:#0184BC"> =</span><span style="color:#A626A4"> new</span><span style="color:#4078F2"> Set</span><span style="color:#383A42">([</span><span style="color:#986801">1</span><span style="color:#383A42">, </span><span style="color:#986801">2</span><span style="color:#383A42">, </span><span style="color:#986801">2</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">]);</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#0184BC">...</span><span style="color:#383A42">uniques];</span>
</span><span class="line">
</span><span class="line"><span style="color:#383A42">uniques; </span><span style="color:#A0A1A7;font-style:italic">// Set (3) {1, 2, 3}</span>
</span><span class="line"><span style="color:#383A42">array; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3]</span></span></code></pre><p>This is useful when you want to concatenate multiple arrays into a single one and remove any duplicate values:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array1</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">1</span><span style="color:#383A42">, </span><span style="color:#986801">2</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> array2</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">2</span><span style="color:#383A42">, </span><span style="color:#986801">3</span><span style="color:#383A42">, </span><span style="color:#986801">4</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> uniques</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#0184BC">...</span><span style="color:#A626A4">new</span><span style="color:#4078F2"> Set</span><span style="color:#383A42">([</span><span style="color:#0184BC">...</span><span style="color:#383A42">array1, </span><span style="color:#0184BC">...</span><span style="color:#383A42">array2])];</span></span></code></pre><p>We're concatenating <code>array1</code> and <code>array2</code> into a new array that contains all six elements: <code>[1, 2, 3, 2, 3, 4]</code>. That new array is passed to the <code>Set</code> constructor. Set can't contain duplicate values, so when we spread the set into the outer new array, we end up with four unique values:</p>
<pre><code class="language-js"><span class="line"><span style="color:#383A42">array1; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3]</span>
</span><span class="line"><span style="color:#383A42">array2; </span><span style="color:#A0A1A7;font-style:italic">// [2, 3, 4]</span>
</span><span class="line"><span style="color:#383A42">uniques; </span><span style="color:#A0A1A7;font-style:italic">// [1, 2, 3, 4]</span></span></code></pre><h2 id="summary"><a class="heading-anchor" href="#summary">#</a>Summary</h2>
<p>We've seen different approaches to concatenate multiple arrays into a single one:</p>
<ul>
<li>Using the <code>Array.prototype.push()</code> method</li>
<li>Using the <code>Array.prototype.concat()</code> method</li>
<li>Using spread syntax in array literals</li>
</ul>
<p>Most importantly, you should remember that the <code>push()</code> mutates the target array, modifying it in place. The <code>concat()</code> method and spread syntax in array literals, on the other hand, are non-mutating; both approaches create a new array instead.</p>
urn:uuid:11a262db-bb6c-42dc-83db-03bcf97b23ecThe Omit Helper Type in TypeScript2020-03-28T00:00:00.000Z2020-08-30T00:00:00.000ZTypeScript 3.5 added an Omit<T, K> helper type which lets us create an object type that omits specific properties from another object type.<p>In version 3.5, TypeScript added an <code>Omit<T, K></code> helper type to the <em>lib.es5.d.ts</em> type definition file that ships as part of the TypeScript compiler. The <code>Omit<T, K></code> type lets us create an object type that omits specific properties from another object type:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> User</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> id</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> name</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> email</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">};</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Omit</span><span style="color:#383A42"><</span><span style="color:#C18401">User</span><span style="color:#383A42">, </span><span style="color:#50A14F">"email"</span><span style="color:#383A42">>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> id</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> name</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>The <code>Omit<T, K></code> helper type is defined in <em>lib.es5.d.ts</em> like this:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">/**</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> * Construct a type with the properties of T except for those in type K.</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> */</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> Omit</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#A626A4"> extends</span><span style="color:#0184BC"> keyof</span><span style="color:#383A42"> any> </span><span style="color:#0184BC">=</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">Exclude</span><span style="color:#383A42"><</span><span style="color:#0184BC">keyof</span><span style="color:#C18401"> T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#383A42">>>;</span></span></code></pre><p>To untangle this type definition and understand how it works, let's see how we could've come up with our own version of the <code>Omit<T, K></code> helper type ourselves.</p>
<h2 id="defining-the-omit-t-k-helper-type"><a class="heading-anchor" href="#defining-the-omit-t-k-helper-type">#</a>Defining the <code>Omit<T, K></code> Helper Type</h2>
<p>Let's start with the same <code>User</code> type we've seen above:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> User</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> id</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> name</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> email</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>First, we need to be able to retrieve all keys of the <code>User</code> type. We can use the <a href="/blog/keyof-and-lookup-types-in-typescript"><code>keyof</code> operator</a> to retrieve a union of <a href="/blog/string-literal-types-in-typescript">string literal types</a> that contains all property keys of this object type:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserKeys</span><span style="color:#0184BC"> =</span><span style="color:#0184BC"> keyof</span><span style="color:#C18401"> User</span><span style="color:#383A42">;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserKeys</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "id"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "name"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "email"</span><span style="color:#383A42">;</span></span></code></pre><p>Next, we need to be able to exclude a specific string literal type from a union of string literal types. In the case of our <code>User</code> type, we want to exclude the type <code>"email"</code> from the union <code>"id" | "name" | "email"</code>. We can use the <code>Exclude<T, U></code> helper type to do that:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserKeysWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Exclude</span><span style="color:#383A42"><</span><span style="color:#C18401">UserKeys</span><span style="color:#383A42">, </span><span style="color:#50A14F">"email"</span><span style="color:#383A42">>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserKeysWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Exclude</span><span style="color:#383A42"><</span><span style="color:#50A14F">"id"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "name"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "email"</span><span style="color:#383A42">, </span><span style="color:#50A14F">"email"</span><span style="color:#383A42">>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserKeysWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "id"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "name"</span><span style="color:#383A42">;</span></span></code></pre><p>The <code>Exclude<T, U></code> type is defined in <em>lib.es5.d.ts</em> like this:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">/**</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> * Exclude from T those types that are assignable to U</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> */</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> Exclude</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">U</span><span style="color:#383A42">> </span><span style="color:#0184BC">=</span><span style="color:#C18401"> T</span><span style="color:#A626A4"> extends</span><span style="color:#C18401"> U</span><span style="color:#0184BC"> ?</span><span style="color:#0184BC"> never</span><span style="color:#0184BC"> :</span><span style="color:#C18401"> T</span><span style="color:#383A42">;</span></span></code></pre><p>It's using a <a href="/blog/conditional-types-in-typescript">conditional type</a> and the <a href="/blog/the-never-type-in-typescript"><code>never</code> type</a>. Using the <code>Exclude<T, U></code> helper type, we're removing those types in our union type <code>"id" | "name" | "email"</code> that are assignable to the <code>"email"</code> type. That is only true for the string literal type <code>"email"</code> itself, so we're left with the union type <code>"id | "name"</code>.</p>
<p>Finally, we need to create an object type that contains a subset of the properties of our <code>User</code> type. Specifically, we want to create an object type that contains only those properties whose keys are found in the <code>UserKeysWithoutEmail</code> union type. We can use the <code>Pick<T, K></code> helper type to pick those properties off of our <code>User</code> type:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">User</span><span style="color:#383A42">, </span><span style="color:#C18401">UserKeysWithoutEmail</span><span style="color:#383A42">>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">User</span><span style="color:#383A42">, </span><span style="color:#50A14F">"id"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "name"</span><span style="color:#383A42">>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> id</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> name</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>Here's how the <code>Pick<T, K></code> helper type is defined within <em>lib.es5.d.ts</em>:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">/**</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> * From T, pick a set of properties whose keys are in the union K</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> */</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#A626A4"> extends</span><span style="color:#0184BC"> keyof</span><span style="color:#C18401"> T</span><span style="color:#383A42">> </span><span style="color:#0184BC">=</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> [</span><span style="color:#C18401">P</span><span style="color:#A626A4"> in</span><span style="color:#C18401"> K</span><span style="color:#383A42">]</span><span style="color:#0184BC">:</span><span style="color:#C18401"> T</span><span style="color:#383A42">[</span><span style="color:#C18401">P</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>The <code>Pick<T, K></code> type is a <a href="/blog/mapped-types-in-typescript">mapped type</a> that's using the <code>keyof</code> operator and an <a href="/blog/keyof-and-lookup-types-in-typescript#indexed-access-types">indexed access type</a> <code>T[P]</code> to retrieve the type of the property <code>P</code> in the object type <code>T</code>.</p>
<p>Now, let's summarize all the type operations we've performed using <code>keyof</code>, <code>Exclude<T, U></code>, and <code>Pick<T, K></code> in a single type:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">User</span><span style="color:#383A42">, </span><span style="color:#C18401">Exclude</span><span style="color:#383A42"><</span><span style="color:#0184BC">keyof</span><span style="color:#C18401"> User</span><span style="color:#383A42">, </span><span style="color:#50A14F">"email"</span><span style="color:#383A42">>>;</span></span></code></pre><p>Notice that this type is specific to our <code>User</code> type. Let's make this a generic type so we can reuse it in other places:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> Omit</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#383A42">> </span><span style="color:#0184BC">=</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">Exclude</span><span style="color:#383A42"><</span><span style="color:#0184BC">keyof</span><span style="color:#C18401"> T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#383A42">>>;</span></span></code></pre><p>We can now use this type to compute our <code>UserWithoutEmail</code> type:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Omit</span><span style="color:#383A42"><</span><span style="color:#C18401">User</span><span style="color:#383A42">, </span><span style="color:#50A14F">"email"</span><span style="color:#383A42">>;</span></span></code></pre><p>Since object keys can only be strings, numbers, or symbols, we can add a generic constraint to the type parameter <code>K</code> of our <code>Omit<T, K></code> helper type to only allow types <code>string</code>, <code>number</code>, or <code>symbol</code> for keys:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> Omit</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#A626A4"> extends</span><span style="color:#383A42"> string </span><span style="color:#0184BC">|</span><span style="color:#383A42"> number </span><span style="color:#0184BC">|</span><span style="color:#383A42"> symbol> </span><span style="color:#0184BC">=</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">Exclude</span><span style="color:#383A42"><</span><span style="color:#0184BC">keyof</span><span style="color:#C18401"> T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#383A42">>>;</span></span></code></pre><p>The generic constraint <code>extends string | number | symbol</code> is a bit verbose. We can replace the <code>string | number | symbol</code> union type by the <code>keyof any</code> type since the two are equivalent:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> Omit</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#A626A4"> extends</span><span style="color:#0184BC"> keyof</span><span style="color:#383A42"> any> </span><span style="color:#0184BC">=</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">Exclude</span><span style="color:#383A42"><</span><span style="color:#0184BC">keyof</span><span style="color:#C18401"> T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#383A42">>>;</span></span></code></pre><p>And there we go! We've arrived at the exact definition of the <code>Omit<T, K></code> helper type as it is found within the <em>lib.es5.d.ts</em> type definition file:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">/**</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> * Construct a type with the properties of T except for those in type K.</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> */</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> Omit</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#A626A4"> extends</span><span style="color:#0184BC"> keyof</span><span style="color:#383A42"> any> </span><span style="color:#0184BC">=</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">T</span><span style="color:#383A42">, </span><span style="color:#C18401">Exclude</span><span style="color:#383A42"><</span><span style="color:#0184BC">keyof</span><span style="color:#C18401"> T</span><span style="color:#383A42">, </span><span style="color:#C18401">K</span><span style="color:#383A42">>>;</span></span></code></pre><h2 id="unrolling-omit-user-email"><a class="heading-anchor" href="#unrolling-omit-user-email">#</a>Unrolling <code>Omit<User, "email"></code></h2>
<p>Here's a step-by-step evaluation of the <code>Omit<User, "email"></code> type. Try to follow every step to understand how TypeScript is computing the final type:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> User</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> id</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> name</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> email</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">};</span>
</span><span class="line">
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Omit</span><span style="color:#383A42"><</span><span style="color:#C18401">User</span><span style="color:#383A42">, </span><span style="color:#50A14F">"email"</span><span style="color:#383A42">>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">User</span><span style="color:#383A42">, </span><span style="color:#C18401">Exclude</span><span style="color:#383A42"><</span><span style="color:#0184BC">keyof</span><span style="color:#C18401"> User</span><span style="color:#383A42">, </span><span style="color:#50A14F">"email"</span><span style="color:#383A42">>>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">User</span><span style="color:#383A42">, </span><span style="color:#C18401">Exclude</span><span style="color:#383A42"><</span><span style="color:#50A14F">"id"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "name"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "email"</span><span style="color:#383A42">, </span><span style="color:#50A14F">"email"</span><span style="color:#383A42">>>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span>
</span><span class="line"><span style="color:#C18401"> User</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#0184BC"> |</span><span style="color:#383A42"> (</span><span style="color:#50A14F">"id"</span><span style="color:#A626A4"> extends</span><span style="color:#50A14F"> "email"</span><span style="color:#0184BC"> ?</span><span style="color:#383A42"> never </span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "id"</span><span style="color:#383A42">)</span>
</span><span class="line"><span style="color:#0184BC"> |</span><span style="color:#383A42"> (</span><span style="color:#50A14F">"name"</span><span style="color:#A626A4"> extends</span><span style="color:#50A14F"> "email"</span><span style="color:#0184BC"> ?</span><span style="color:#383A42"> never </span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "name"</span><span style="color:#383A42">)</span>
</span><span class="line"><span style="color:#0184BC"> |</span><span style="color:#383A42"> (</span><span style="color:#50A14F">"email"</span><span style="color:#A626A4"> extends</span><span style="color:#50A14F"> "email"</span><span style="color:#0184BC"> ?</span><span style="color:#383A42"> never </span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "email"</span><span style="color:#383A42">)</span>
</span><span class="line"><span style="color:#383A42">>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">User</span><span style="color:#383A42">, </span><span style="color:#50A14F">"id"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "name"</span><span style="color:#0184BC"> |</span><span style="color:#383A42"> never>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#C18401"> Pick</span><span style="color:#383A42"><</span><span style="color:#C18401">User</span><span style="color:#383A42">, </span><span style="color:#50A14F">"id"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "name"</span><span style="color:#383A42">>;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> [</span><span style="color:#C18401">P</span><span style="color:#A626A4"> in</span><span style="color:#50A14F"> "id"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "name"</span><span style="color:#383A42">]</span><span style="color:#0184BC">:</span><span style="color:#C18401"> User</span><span style="color:#383A42">[</span><span style="color:#C18401">P</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#383A42">};</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> id</span><span style="color:#0184BC">:</span><span style="color:#C18401"> User</span><span style="color:#383A42">[</span><span style="color:#50A14F">"id"</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#383A42"> name</span><span style="color:#0184BC">:</span><span style="color:#C18401"> User</span><span style="color:#383A42">[</span><span style="color:#50A14F">"name"</span><span style="color:#383A42">];</span>
</span><span class="line"><span style="color:#383A42">};</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// This is equivalent to:</span>
</span><span class="line"><span style="color:#A626A4">type</span><span style="color:#C18401"> UserWithoutEmail</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#383A42"> id</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> name</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>Et voilà, our final <code>UserWithoutEmail</code> type.</p>
urn:uuid:11a77245-32cc-4cb5-a67b-1bb229b3ec05Fast Searching with ripgrep2020-03-19T00:00:00.000Z2020-04-16T00:00:00.000ZIn this post, I want to introduce you to ripgrep, a smart and fast command line search tool that I find myself using all the time when programming.<p>In this post, I want to introduce you to <a href="https://github.com/BurntSushi/ripgrep">ripgrep</a>, a smart and fast command line search tool that I find myself using all the time when programming. ripgrep recursively searches directories for a regex pattern and outputs all matches that it finds.</p>
<h2 id="why-ripgrep"><a class="heading-anchor" href="#why-ripgrep">#</a>Why ripgrep?</h2>
<p>So what makes ripgrep so great? After all, there are plenty of other search tools out there already, like <a href="https://www.gnu.org/savannah-checkouts/gnu/grep/">grep</a>, <a href="https://beyondgrep.com/">ack</a>, or <a href="https://github.com/ggreer/the_silver_searcher">The Silver Searcher</a>. For me, it boils down to the following reasons:</p>
<ul>
<li><strong>ripgrep is smart.</strong> It picks sensible defaults out of the box. I like that! For example, ripgrep respects <code>.gitignore</code> files and skips matching files and directories by default. It also ignores binary files, skips hidden files and directories, and doesn't follow symbolic links.</li>
<li><strong>ripgrep is fast.</strong> In fact, it's <em>very</em> fast. I've thrown hundreds of thousands of files at it and didn't encounter any performance issues. Check out <a href="https://blog.burntsushi.net/ripgrep/">ripgrep is faster than {grep, ag, git grep, ucg, pt, sift}</a> for a detailed analysis and various performance benchmarks.</li>
</ul>
<p>ripgrep also has full Unicode support, can search compressed files, and optionally lets you switch its regex engine to use <a href="https://www.pcre.org/current/doc/html/pcre2syntax.html">PCRE2 regular expressions</a>.</p>
<h2 id="installation"><a class="heading-anchor" href="#installation">#</a>Installation</h2>
<p>If you're using <a href="https://brew.sh/">Homebrew</a>, you can run the following command to install ripgrep:</p>
<pre><code><span class="line"><span>$ brew install ripgrep</span></span></code></pre><p>If you're using a different package manager, you can find a comprehensive list of installation instructions in the <a href="https://github.com/BurntSushi/ripgrep#installation">README.md</a> on GitHub.</p>
<h2 id="the-basics"><a class="heading-anchor" href="#the-basics">#</a>The Basics</h2>
<p>The name of the ripgrep executable is <code>rg</code>. In its most basic form, a simple search can look like this:</p>
<pre><code><span class="line"><span>$ rg '// TODO'</span></span></code></pre><p>This command will recursively search all files in the current directory (and its subdirectories) for the string <code>// TODO</code> and output the matches that it finds. If I run this command within the <em>src</em> directory of the <a href="https://github.com/prettier/prettier">prettier repository</a>, the output looks like this:</p>
<pre><code><span class="line"><span>$ rg '// TODO'</span>
</span><span class="line"><span>language-css/parser-postcss.js</span>
</span><span class="line"><span>521: // TODO: Remove this hack when this issue is fixed:</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-markdown/parser-markdown.js</span>
</span><span class="line"><span>121: // TODO: Delete this in 2.0</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-handlebars/parser-glimmer.js</span>
</span><span class="line"><span>32: // TODO: `locStart` and `locEnd` should return a number offset</span>
</span><span class="line"><span></span>
</span><span class="line"><span>common/util-shared.js</span>
</span><span class="line"><span>42: mapDoc, // TODO: remove in 2.0, we already exposed it in docUtils</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-js/utils.js</span>
</span><span class="line"><span>239:// TODO: This is a bad hack and we need a better way to distinguish between</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-html/utils.js</span>
</span><span class="line"><span>80: // TODO: handle non-text children in <pre></span>
</span><span class="line"><span></span>
</span><span class="line"><span>common/internal-plugins.js</span>
</span><span class="line"><span>91: // TODO: switch these to just `postcss` and use `language` instead.</span>
</span><span class="line"><span>134: // TODO: Delete this in 2.0</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-html/constants.evaluate.js</span>
</span><span class="line"><span>21: // TODO: send PR to upstream</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-js/printer-estree.js</span>
</span><span class="line"><span>5:// TODO(azz): anything that imports from main shouldn't be in a `language-*` dir.</span></span></code></pre><p>The matches are grouped by file name. For each match, ripgrep prints the line number and highlights the matching substring.</p>
<h2 id="frequently-used-options"><a class="heading-anchor" href="#frequently-used-options">#</a>Frequently Used Options</h2>
<p>For the remainder of this article, I'll go over several ripgrep options that I find myself using frequently to perform various search tasks when programming. I'm using the <a href="https://github.com/prettier/prettier">prettier repository</a> to demonstrate the different options and what effect they have.</p>
<p>Feel free to clone the repository and follow along:</p>
<pre><code><span class="line"><span>$ git clone https://github.com/prettier/prettier.git</span>
</span><span class="line"><span>$ cd prettier</span></span></code></pre><p>Also, unless stated otherwise, I'm running all commands from within the <em>src</em> directory:</p>
<pre><code><span class="line"><span>$ cd src</span></span></code></pre><h2 id="no-options"><a class="heading-anchor" href="#no-options">#</a>No Options</h2>
<p>Let's start with running ripgrep without any options. The default behavior might do exactly what you want already. Here, I am searching for the string <code>// TODO</code> within the current working directory:</p>
<pre><code><span class="line"><span>$ rg '// TODO'</span>
</span><span class="line"><span>language-css/parser-postcss.js</span>
</span><span class="line"><span>521: // TODO: Remove this hack when this issue is fixed:</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-markdown/parser-markdown.js</span>
</span><span class="line"><span>121: // TODO: Delete this in 2.0</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-handlebars/parser-glimmer.js</span>
</span><span class="line"><span>32: // TODO: `locStart` and `locEnd` should return a number offset</span>
</span><span class="line"><span></span>
</span><span class="line"><span>common/util-shared.js</span>
</span><span class="line"><span>42: mapDoc, // TODO: remove in 2.0, we already exposed it in docUtils</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-js/utils.js</span>
</span><span class="line"><span>239:// TODO: This is a bad hack and we need a better way to distinguish between</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-html/utils.js</span>
</span><span class="line"><span>80: // TODO: handle non-text children in <pre></span>
</span><span class="line"><span></span>
</span><span class="line"><span>common/internal-plugins.js</span>
</span><span class="line"><span>91: // TODO: switch these to just `postcss` and use `language` instead.</span>
</span><span class="line"><span>134: // TODO: Delete this in 2.0</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-html/constants.evaluate.js</span>
</span><span class="line"><span>21: // TODO: send PR to upstream</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-js/printer-estree.js</span>
</span><span class="line"><span>5:// TODO(azz): anything that imports from main shouldn't be in a `language-*` dir.</span></span></code></pre><p>We can see all matches, grouped by file name, with line numbers and highlighted matching substrings. If you want to quickly find a given string in a bunch of files and directories, this could be sufficient already.</p>
<h2 id="files-with-matches"><a class="heading-anchor" href="#files-with-matches">#</a>Files with Matches</h2>
<p>Sometimes, you're not interested in seeing the matches themselves, but rather the paths of all files that contain at least one match. You can use the <code>--files-with-matches</code> option for that, or <code>-l</code> for short:</p>
<pre><code><span class="line"><span>$ rg -l '// TODO'</span>
</span><span class="line"><span>language-markdown/parser-markdown.js</span>
</span><span class="line"><span>common/util-shared.js</span>
</span><span class="line"><span>language-html/constants.evaluate.js</span>
</span><span class="line"><span>language-css/parser-postcss.js</span>
</span><span class="line"><span>common/internal-plugins.js</span>
</span><span class="line"><span>language-js/printer-estree.js</span>
</span><span class="line"><span>language-html/utils.js</span>
</span><span class="line"><span>language-js/utils.js</span>
</span><span class="line"><span>language-handlebars/parser-glimmer.js</span></span></code></pre><p>Note that ripgrep doesn't emit the files in a specific sort order by default. This is for performance reasons. If you want the list of file paths to be sorted alphabetically, you can use the <code>--sort path</code> option:</p>
<pre><code><span class="line"><span>$ rg -l '// TODO' --sort path</span>
</span><span class="line"><span>common/internal-plugins.js</span>
</span><span class="line"><span>common/util-shared.js</span>
</span><span class="line"><span>language-css/parser-postcss.js</span>
</span><span class="line"><span>language-handlebars/parser-glimmer.js</span>
</span><span class="line"><span>language-html/constants.evaluate.js</span>
</span><span class="line"><span>language-html/utils.js</span>
</span><span class="line"><span>language-js/printer-estree.js</span>
</span><span class="line"><span>language-js/utils.js</span>
</span><span class="line"><span>language-markdown/parser-markdown.js</span></span></code></pre><p>Please be aware that using the <code>--sort path</code> option <a href="https://github.com/BurntSushi/ripgrep/issues/152">disables all parallelism</a> in ripgrep. Unless you're searching a large number of files though, you likely won't notice much of a performance difference.</p>
<p>The <code>-l</code> flag is particularly useful to pipe ripgrep's output into another program and perform additional operations on the matching files. For example, you could use ripgrep to find all files matching the string <code>@format</code> and format them with Prettier using the <code>prettier</code> executable:</p>
<pre><code><span class="line"><span>$ rg -l '@format' | xargs prettier --write</span></span></code></pre><h2 id="files-without-a-match"><a class="heading-anchor" href="#files-without-a-match">#</a>Files Without a Match</h2>
<p>Sometimes, you might not be interested in files that <em>do</em> contain a match, but rather in those that <em>don't</em>. The <code>--files-without-match</code> option outputs exactly those files. Unlike the <code>--files-with-matches</code> option, the <code>--files-without-match</code> option does not have a short alias.</p>
<p>The following command lists all files that don't contain any of the strings <code>var</code>, <code>let</code>, or <code>const</code>. These JavaScript files don't contain any local variable declarations:</p>
<pre><code><span class="line"><span>$ rg --files-without-match '\b(var|let|const)\b'</span>
</span><span class="line"><span>language-yaml/pragma.js</span>
</span><span class="line"><span>language-graphql/pragma.js</span>
</span><span class="line"><span>document/index.js</span>
</span><span class="line"><span>utils/get-last.js</span>
</span><span class="line"><span>language-js/preprocess.js</span>
</span><span class="line"><span>common/internal-plugins.js</span>
</span><span class="line"><span>common/third-party.js</span>
</span><span class="line"><span>utils/arrayify.js</span>
</span><span class="line"><span>language-html/pragma.js</span>
</span><span class="line"><span>common/errors.js</span>
</span><span class="line"><span>language-html/clean.js</span></span></code></pre><p>And again, we can sort the list of files by using the <code>--sort path</code> option:</p>
<pre><code><span class="line"><span>$ rg --files-without-match '\b(var|let|const)\b' --sort path</span>
</span><span class="line"><span>common/errors.js</span>
</span><span class="line"><span>common/internal-plugins.js</span>
</span><span class="line"><span>common/third-party.js</span>
</span><span class="line"><span>document/index.js</span>
</span><span class="line"><span>language-graphql/pragma.js</span>
</span><span class="line"><span>language-html/clean.js</span>
</span><span class="line"><span>language-html/pragma.js</span>
</span><span class="line"><span>language-js/preprocess.js</span>
</span><span class="line"><span>language-yaml/pragma.js</span>
</span><span class="line"><span>utils/arrayify.js</span>
</span><span class="line"><span>utils/get-last.js</span></span></code></pre><p>Notice that we're using several regular expression features in our search pattern:</p>
<ul>
<li><code>\b</code> matches a <a href="https://www.regular-expressions.info/wordboundaries.html">word boundary</a>. That way, the string <code>delete</code> won't match the <code>let</code> pattern.</li>
<li><code>|</code> denotes an <a href="https://www.regular-expressions.info/alternation.html">alternation</a>. The pattern <code>var|let|const</code> matches any string that matches any of the patterns <code>var</code>, <code>let</code>, or <code>const</code>.</li>
</ul>
<p>ripgrep will treat the search pattern as a regular expression by default; there's no need to specify another flag to turn the search pattern into a regular expression.</p>
<h2 id="inverting-matches"><a class="heading-anchor" href="#inverting-matches">#</a>Inverting Matches</h2>
<p>Sometimes, you might be interested in all lines that do <em>not</em> match a given pattern, rather than those lines that do. ripgrep lets us show those lines using the <code>--invert-match</code> (or <code>-v</code> for short) flag.</p>
<p>Every now and then, I want to run a sanity check on all lines of code I've changed in a given Git commit. This is particularly helpful when running a codemod that changes hundreds or thousands of files. In those cases, I want to see a sorted and de-duplicated list of all changed lines. Here's the command I use:</p>
<pre><code><span class="line"><span>git show | rg '^[-+]' | rg -v '^[-+]{3}' | sort | uniq</span></span></code></pre><p>For the commit <a href="https://github.com/prettier/prettier/commit/6daa7e199e2d71cee66f5ebee3b2efe4648d7b99">6daa7e199e2d71cee66f5ebee3b2efe4648d7b99</a> in the Prettier repository, this is the output:</p>
<pre><code><span class="line"><span>+ - "patch-release"</span>
</span><span class="line"><span>- - patch-release</span></span></code></pre><p>If I were to remove the <code>rg -v '^[-+]{3}'</code> bit from the pipe, the output would include file names as well, which is not what I want:</p>
<pre><code><span class="line"><span>+ - "patch-release"</span>
</span><span class="line"><span>+++ b/.github/workflows/dev-test.yml</span>
</span><span class="line"><span>+++ b/.github/workflows/lint.yml</span>
</span><span class="line"><span>+++ b/.github/workflows/prod-test.yml</span>
</span><span class="line"><span>- - patch-release</span>
</span><span class="line"><span>--- a/.github/workflows/dev-test.yml</span>
</span><span class="line"><span>--- a/.github/workflows/lint.yml</span>
</span><span class="line"><span>--- a/.github/workflows/prod-test.yml</span></span></code></pre><p>By piping the output of the first search through <code>rg -v '^[-+]{3}'</code>, I'm excluding all lines that start with three pluses or minuses, giving me a cleaner output at the end.</p>
<h2 id="fixed-strings"><a class="heading-anchor" href="#fixed-strings">#</a>Fixed Strings</h2>
<p>Usually, it's useful that ripgrep treats every search pattern as a regular expression by default. We've seen in the previous section how we can search for several strings using the pattern <code>var|let|const</code> using an alternation, and there was no need for an additional flag to tell ripgrep to interpret the pattern as a regular expression rather than a fixed string.</p>
<p>However, if we want to search for a string that is not a well-formed regular expression, we get an error:</p>
<pre><code><span class="line"><span>$ rg '?.'</span>
</span><span class="line"><span>regex parse error:</span>
</span><span class="line"><span> ?.</span>
</span><span class="line"><span> ^</span>
</span><span class="line"><span>error: repetition operator missing expression</span></span></code></pre><p>In the above example, our search for the pattern <code>?.</code> failed because the pattern is malformed. In a regular expression, the <code>?</code> character denotes a repetition operator that makes the previous expression optional. It must follow an expression, which it doesn't do here.</p>
<p>We can tell ripgrep that we want it to interpret the search string as a fixed string rather than a regular expression pattern. All characters that would have special meaning in a regular expression (e.g. <code>$</code>, <code>?</code>, <code>|</code>, …) will be matched verbatim. The flag we need to use to turn on this behavior is called <code>--fixed-strings</code>, or <code>-F</code> for short:</p>
<pre><code><span class="line"><span>$ rg -F '?.'</span>
</span><span class="line"><span>language-js/printer-estree.js</span>
</span><span class="line"><span>4763: return "?.";</span></span></code></pre><p>Now, the search has succeeded and we get all results matching the string <code>?.</code> verbatim.</p>
<h2 id="context-around-a-match"><a class="heading-anchor" href="#context-around-a-match">#</a>Context Around a Match</h2>
<p>Sometimes, seeing only the matching lines themselves without any preceding or following lines might lack context. Take the search for <code>// TODO</code> as an example again:</p>
<pre><code><span class="line"><span>$ rg '// TODO'</span>
</span><span class="line"><span>language-css/parser-postcss.js</span>
</span><span class="line"><span>521: // TODO: Remove this hack when this issue is fixed:</span>
</span><span class="line"><span></span>
</span><span class="line"><span>common/util-shared.js</span>
</span><span class="line"><span>42: mapDoc, // TODO: remove in 2.0, we already exposed it in docUtils</span>
</span><span class="line"><span></span>
</span><span class="line"><span>common/internal-plugins.js</span>
</span><span class="line"><span>91: // TODO: switch these to just `postcss` and use `language` instead.</span>
</span><span class="line"><span>134: // TODO: Delete this in 2.0</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-markdown/parser-markdown.js</span>
</span><span class="line"><span>121: // TODO: Delete this in 2.0</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-handlebars/parser-glimmer.js</span>
</span><span class="line"><span>32: // TODO: `locStart` and `locEnd` should return a number offset</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-js/utils.js</span>
</span><span class="line"><span>239:// TODO: This is a bad hack and we need a better way to distinguish between</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-js/printer-estree.js</span>
</span><span class="line"><span>5:// TODO(azz): anything that imports from main shouldn't be in a `language-*` dir.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-html/constants.evaluate.js</span>
</span><span class="line"><span>21: // TODO: send PR to upstream</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-html/utils.js</span>
</span><span class="line"><span>80: // TODO: handle non-text children in <pre></span></span></code></pre><p>Wouldn't it be helpful if we could see a few lines following each <code>// TODO</code> comment to get an idea of the code to which each comment refers? It turns out that ripgrep can do that. We can specify the <code>--context</code> option (or <code>-C</code> for short) and pass it an argument <code>N</code> to have ripgrep display <code>N</code> lines before and after each matching line:</p>
<pre><code><span class="line"><span>$ rg '// TODO' -C 2</span>
</span><span class="line"><span>language-css/parser-postcss.js</span>
</span><span class="line"><span>519- }</span>
</span><span class="line"><span>520-</span>
</span><span class="line"><span>521: // TODO: Remove this hack when this issue is fixed:</span>
</span><span class="line"><span>522- // https://github.com/shellscape/postcss-less/issues/88</span>
</span><span class="line"><span>523- const LessParser = require("postcss-less/dist/less-parser");</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-markdown/parser-markdown.js</span>
</span><span class="line"><span>119- parsers: {</span>
</span><span class="line"><span>120- remark: markdownParser,</span>
</span><span class="line"><span>121: // TODO: Delete this in 2.0</span>
</span><span class="line"><span>122- markdown: markdownParser,</span>
</span><span class="line"><span>123- mdx: mdxParser</span>
</span><span class="line"><span></span>
</span><span class="line"><span>common/util-shared.js</span>
</span><span class="line"><span>40- isPreviousLineEmpty,</span>
</span><span class="line"><span>41- getNextNonSpaceNonCommentCharacterIndex,</span>
</span><span class="line"><span>42: mapDoc, // TODO: remove in 2.0, we already exposed it in docUtils</span>
</span><span class="line"><span>43- makeString: util.makeString,</span>
</span><span class="line"><span>44- addLeadingComment: util.addLeadingComment,</span>
</span><span class="line"><span></span>
</span><span class="line"><span>common/internal-plugins.js</span>
</span><span class="line"><span>89- {</span>
</span><span class="line"><span>90- parsers: {</span>
</span><span class="line"><span>91: // TODO: switch these to just `postcss` and use `language` instead.</span>
</span><span class="line"><span>92- get css() {</span>
</span><span class="line"><span>93- return eval("require")("../language-css/parser-postcss").parsers.css;</span>
</span><span class="line"><span>--</span>
</span><span class="line"><span>132- .remark;</span>
</span><span class="line"><span>133- },</span>
</span><span class="line"><span>134: // TODO: Delete this in 2.0</span>
</span><span class="line"><span>135- get markdown() {</span>
</span><span class="line"><span>136- return eval("require")("../language-markdown/parser-markdown").parsers</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-js/utils.js</span>
</span><span class="line"><span>237-}</span>
</span><span class="line"><span>238-</span>
</span><span class="line"><span>239:// TODO: This is a bad hack and we need a better way to distinguish between</span>
</span><span class="line"><span>240-// arrow functions and otherwise</span>
</span><span class="line"><span>241-function isFunctionNotation(node, options) {</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-handlebars/parser-glimmer.js</span>
</span><span class="line"><span>30- parse,</span>
</span><span class="line"><span>31- astFormat: "glimmer",</span>
</span><span class="line"><span>32: // TODO: `locStart` and `locEnd` should return a number offset</span>
</span><span class="line"><span>33- // https://prettier.io/docs/en/plugins.html#parsers</span>
</span><span class="line"><span>34- // but we need access to the original text to use</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-html/constants.evaluate.js</span>
</span><span class="line"><span>19-</span>
</span><span class="line"><span>20-const CSS_DISPLAY_TAGS = Object.assign({}, getCssStyleTags("display"), {</span>
</span><span class="line"><span>21: // TODO: send PR to upstream</span>
</span><span class="line"><span>22- button: "inline-block",</span>
</span><span class="line"><span>23-</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-html/utils.js</span>
</span><span class="line"><span>78- }</span>
</span><span class="line"><span>79-</span>
</span><span class="line"><span>80: // TODO: handle non-text children in <pre></span>
</span><span class="line"><span>81- if (</span>
</span><span class="line"><span>82- isPreLikeNode(node) &&</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-js/printer-estree.js</span>
</span><span class="line"><span>3-const assert = require("assert");</span>
</span><span class="line"><span>4-</span>
</span><span class="line"><span>5:// TODO(azz): anything that imports from main shouldn't be in a `language-*` dir.</span>
</span><span class="line"><span>6-const comments = require("../main/comments");</span>
</span><span class="line"><span>7-const {</span></span></code></pre><p>Now, we can see two lines before and after each <code>// TODO</code> comment, giving us some more context without having to open those files.</p>
<p>If you want to control the number of lines before and after the matching line independently, you can use the <code>--before-context</code> and <code>--after-context</code> options, respectively, or <code>-B</code> and <code>-A</code> for short. For example, here are all <code>// TODO</code> comments, followed by the next three lines:</p>
<pre><code><span class="line"><span>$ rg '// TODO' -A 3</span>
</span><span class="line"><span>language-markdown/parser-markdown.js</span>
</span><span class="line"><span>121: // TODO: Delete this in 2.0</span>
</span><span class="line"><span>122- markdown: markdownParser,</span>
</span><span class="line"><span>123- mdx: mdxParser</span>
</span><span class="line"><span>124- }</span>
</span><span class="line"><span></span>
</span><span class="line"><span>common/util-shared.js</span>
</span><span class="line"><span>42: mapDoc, // TODO: remove in 2.0, we already exposed it in docUtils</span>
</span><span class="line"><span>43- makeString: util.makeString,</span>
</span><span class="line"><span>44- addLeadingComment: util.addLeadingComment,</span>
</span><span class="line"><span>45- addDanglingComment: util.addDanglingComment,</span>
</span><span class="line"><span></span>
</span><span class="line"><span>common/internal-plugins.js</span>
</span><span class="line"><span>91: // TODO: switch these to just `postcss` and use `language` instead.</span>
</span><span class="line"><span>92- get css() {</span>
</span><span class="line"><span>93- return eval("require")("../language-css/parser-postcss").parsers.css;</span>
</span><span class="line"><span>94- },</span>
</span><span class="line"><span>--</span>
</span><span class="line"><span>134: // TODO: Delete this in 2.0</span>
</span><span class="line"><span>135- get markdown() {</span>
</span><span class="line"><span>136- return eval("require")("../language-markdown/parser-markdown").parsers</span>
</span><span class="line"><span>137- .remark;</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-handlebars/parser-glimmer.js</span>
</span><span class="line"><span>32: // TODO: `locStart` and `locEnd` should return a number offset</span>
</span><span class="line"><span>33- // https://prettier.io/docs/en/plugins.html#parsers</span>
</span><span class="line"><span>34- // but we need access to the original text to use</span>
</span><span class="line"><span>35- // `loc.start` and `loc.end` objects to calculate the offset</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-js/utils.js</span>
</span><span class="line"><span>239:// TODO: This is a bad hack and we need a better way to distinguish between</span>
</span><span class="line"><span>240-// arrow functions and otherwise</span>
</span><span class="line"><span>241-function isFunctionNotation(node, options) {</span>
</span><span class="line"><span>242- return isGetterOrSetter(node) || sameLocStart(node, node.value, options);</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-js/printer-estree.js</span>
</span><span class="line"><span>5:// TODO(azz): anything that imports from main shouldn't be in a `language-*` dir.</span>
</span><span class="line"><span>6-const comments = require("../main/comments");</span>
</span><span class="line"><span>7-const {</span>
</span><span class="line"><span>8- getParentExportDeclaration,</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-css/parser-postcss.js</span>
</span><span class="line"><span>521: // TODO: Remove this hack when this issue is fixed:</span>
</span><span class="line"><span>522- // https://github.com/shellscape/postcss-less/issues/88</span>
</span><span class="line"><span>523- const LessParser = require("postcss-less/dist/less-parser");</span>
</span><span class="line"><span>524- LessParser.prototype.atrule = function() {</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-html/constants.evaluate.js</span>
</span><span class="line"><span>21: // TODO: send PR to upstream</span>
</span><span class="line"><span>22- button: "inline-block",</span>
</span><span class="line"><span>23-</span>
</span><span class="line"><span>24- // special cases for some css display=none elements</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-html/utils.js</span>
</span><span class="line"><span>80: // TODO: handle non-text children in <pre></span>
</span><span class="line"><span>81- if (</span>
</span><span class="line"><span>82- isPreLikeNode(node) &&</span>
</span><span class="line"><span>83- node.children.some(</span></span></code></pre><h2 id="specific-file-types-only"><a class="heading-anchor" href="#specific-file-types-only">#</a>Specific File Types Only</h2>
<p>The <code>--type</code> option, or <code>-t</code> for short, lets you restrict searches to files of a specific type. To see how this option works, let's move up one level from the <em>src</em> directory into the root of the prettier repository:</p>
<pre><code><span class="line"><span>$ cd ..</span></span></code></pre><p>Let's confirm the current working directory:</p>
<pre><code><span class="line"><span>$ pwd</span>
</span><span class="line"><span>/Users/marius/code/prettier</span></span></code></pre><p>Alright, now we're ready. We can run a search for <code>@format</code> only on JavaScript files:</p>
<pre><code><span class="line"><span>$ rg -t js '@format'</span>
</span><span class="line"><span>src/language-yaml/pragma.js</span>
</span><span class="line"><span>12: return `# @format\n\n${text}`;</span>
</span><span class="line"><span></span>
</span><span class="line"><span>src/language-graphql/pragma.js</span>
</span><span class="line"><span>8: return "# @format\n\n" + text;</span>
</span><span class="line"><span></span>
</span><span class="line"><span>src/language-css/clean.js</span>
</span><span class="line"><span>35: * @format</span>
</span><span class="line"><span></span>
</span><span class="line"><span>src/language-html/pragma.js</span>
</span><span class="line"><span>8: return "<!-- @format -->\n\n" + text.replace(/^\s*\n/, "");</span>
</span><span class="line"><span></span>
</span><span class="line"><span>src/main/core-options.js</span>
</span><span class="line"><span>110: description: "Insert @format pragma into file's first docblock comment.",</span>
</span><span class="line"><span>234: Require either '@prettier' or '@format' to be present in the file's first docblock comment</span>
</span><span class="line"><span></span>
</span><span class="line"><span>tests/insert-pragma/js/module-with-pragma.js</span>
</span><span class="line"><span>5: * @format</span>
</span><span class="line"><span></span>
</span><span class="line"><span>tests/require-pragma/js/module-with-pragma.js</span>
</span><span class="line"><span>3: * @format</span></span></code></pre><p>Or we could search within Markdown files only:</p>
<pre><code><span class="line"><span>$ rg -t md '@format'</span>
</span><span class="line"><span>docs/cli.md</span>
</span><span class="line"><span>101:Valid pragmas are `@prettier` and `@format`.</span>
</span><span class="line"><span>105:Insert a `@format` pragma to the top of formatted files when pragma is absent. Works well when used in tandem with `--require-pragma`.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>docs/options.md</span>
</span><span class="line"><span>258: * @format</span>
</span><span class="line"><span>270:Prettier can insert a special @format marker at the top of files specifying that the file has been formatted with prettier. This works well when used in tandem with the `--require-pragma` option. If there is already a docblock at the top of the file then this option will add a newline to it with the @format marker.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>website/blog/2017-09-15-1.7.0.md</span>
</span><span class="line"><span>108: * @format</span>
</span><span class="line"><span>187:- [**Add option to require @prettier or @format pragma**](https://github.com/prettier/prettier/pull/2772) by [@wbinnssmith](https://github.com/wbinnssmith)</span>
</span><span class="line"><span></span>
</span><span class="line"><span>website/blog/2017-05-03-1.3.0.md</span>
</span><span class="line"><span>25:- When pretty-printing a file, add `@format` to the first block comment like `@flow`.</span>
</span><span class="line"><span>26:- Have a lint rule with autofix that checks if the file is correctly pretty printed when `@format` is present.</span>
</span><span class="line"><span>29:- Update the default code templates to add `@format` to the header.</span>
</span><span class="line"><span>30:- When you run code formatting via cmd-shift-c inside of Nuclide, automatically insert the `@format` header.</span>
</span><span class="line"><span>31:- Disable all the stylistic rules like max-len when `@format` is in the header.</span>
</span><span class="line"><span>34:- When pushing a new release of prettier, also run it through all the files with `@format` in order to avoid getting warnings afterwards.</span>
</span><span class="line"><span>35:- Add tracking for the number of files with `@format` over time.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>website/blog/2017-11-07-1.8.0.md</span>
</span><span class="line"><span>136:#### Add option to insert `@format` to first docblock if absent ([#2865](https://github.com/prettier/prettier/pull/2865)) by [@samouri](https://github.com/samouri)</span>
</span><span class="line"><span>138:In 1.7, we added an option called `--require-pragma` to require files contain an `/** @format */` pragma to be formatted. In order to add this pragma to a large set of files you can now use [`--insert-pragma`](https://prettier.io/docs/en/cli.html#insert-pragma) flag.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>website/blog/2018-02-26-1.11.0.md</span>
</span><span class="line"><span>814: * @format</span>
</span><span class="line"><span>820: * @format</span>
</span><span class="line"><span></span>
</span><span class="line"><span>website/versioned_docs/version-stable/cli.md</span>
</span><span class="line"><span>102:Valid pragmas are `@prettier` and `@format`.</span>
</span><span class="line"><span>106:Insert a `@format` pragma to the top of formatted files when pragma is absent. Works well when used in tandem with `--require-pragma`.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>website/versioned_docs/version-stable/options.md</span>
</span><span class="line"><span>259: * @format</span>
</span><span class="line"><span>271:Prettier can insert a special @format marker at the top of files specifying that the file has been formatted with prettier. This works well when used in tandem with the `--require-pragma` option. If there is already a docblock at the top of the file then this option will add a newline to it with the @format marker.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>tests/markdown/real-world-case.md</span>
</span><span class="line"><span>292:Valid pragmas are `@prettier` and `@format`.</span>
</span><span class="line"><span>695: * @format</span>
</span><span class="line"><span></span>
</span><span class="line"><span>tests/require-pragma/markdown/with-pragma-in-multiline.md</span>
</span><span class="line"><span>6: @format</span></span></code></pre><p>Note that the type specifiers <code>js</code> and <code>md</code> are not file name extensions themselves. The type specifiers represent a set of file name extensions that are considered to be of that type:</p>
<ul>
<li><code>js</code> represents the extensions <em>*.js</em>, <em>*.jsx</em>, and <em>*.vue</em></li>
<li><code>md</code> represents the extensions <em>*.markdown</em>, <em>*.md</em>, <em>*.mdown</em>, and <em>*.mkdn</em></li>
</ul>
<p>You can pull up the complete list of supported type specifiers and the corresponding file name extensions by running the <code>rg --type-list</code> command.</p>
<h2 id="using-a-glob"><a class="heading-anchor" href="#using-a-glob">#</a>Using a Glob</h2>
<p>Sometimes, using the <code>--type</code> (or <code>-t</code> for short) option might not give you enough control over which files to include in the search. In those cases, you can use the <code>--glob</code> (or <code>-g</code> for short) option. ripgrep will only search files whose paths match the specified glob.</p>
<p>For example, you could run a search for <code>// TODO</code> comments within only those JavaScript files whose name starts with "parser-":</p>
<pre><code><span class="line"><span>$ rg -g 'parser-*.js' '// TODO'</span>
</span><span class="line"><span>language-markdown/parser-markdown.js</span>
</span><span class="line"><span>121: // TODO: Delete this in 2.0</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-handlebars/parser-glimmer.js</span>
</span><span class="line"><span>32: // TODO: `locStart` and `locEnd` should return a number offset</span>
</span><span class="line"><span></span>
</span><span class="line"><span>language-css/parser-postcss.js</span>
</span><span class="line"><span>521: // TODO: Remove this hack when this issue is fixed:</span></span></code></pre><h2 id="showing-the-help-page"><a class="heading-anchor" href="#showing-the-help-page">#</a>Showing the Help Page</h2>
<p>Lastly, if you ever forget what a specific option is called, or if you want to see what other options are available, ripgrep provides two different levels of help:</p>
<ul>
<li><code>rg -h</code>: short descriptions with a condensed layout</li>
<li><code>rg --help</code>: long descriptions with detailed explanations</li>
</ul>
<p>Here's what ripgrep 12.0.0 prints when running the <code>rg -h</code> command:</p>
<pre><code><span class="line"><span>ripgrep 12.0.0</span>
</span><span class="line"><span>Andrew Gallant <jamslam@gmail.com></span>
</span><span class="line"><span></span>
</span><span class="line"><span>ripgrep (rg) recursively searches your current directory for a regex pattern.</span>
</span><span class="line"><span>By default, ripgrep will respect your .gitignore and automatically skip hidden</span>
</span><span class="line"><span>files/directories and binary files.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>ripgrep's default regex engine uses finite automata and guarantees linear</span>
</span><span class="line"><span>time searching. Because of this, features like backreferences and arbitrary</span>
</span><span class="line"><span>look-around are not supported. However, if ripgrep is built with PCRE2, then</span>
</span><span class="line"><span>the --pcre2 flag can be used to enable backreferences and look-around.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>ripgrep supports configuration files. Set RIPGREP_CONFIG_PATH to a</span>
</span><span class="line"><span>configuration file. The file can specify one shell argument per line. Lines</span>
</span><span class="line"><span>starting with '#' are ignored. For more details, see the man page or the</span>
</span><span class="line"><span>README.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>ripgrep will automatically detect if stdin exists and search stdin for a regex</span>
</span><span class="line"><span>pattern, e.g. 'ls | rg foo'. In some environments, stdin may exist when it</span>
</span><span class="line"><span>shouldn't. To turn off stdin detection explicitly specify the directory to</span>
</span><span class="line"><span>search, e.g. 'rg foo ./'.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>Tip: to disable all smart filtering and make ripgrep behave a bit more like</span>
</span><span class="line"><span>classical grep, use 'rg -uuu'.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>Project home page: https://github.com/BurntSushi/ripgrep</span>
</span><span class="line"><span></span>
</span><span class="line"><span>Use -h for short descriptions and --help for more details.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>USAGE:</span>
</span><span class="line"><span> rg [OPTIONS] PATTERN [PATH ...]</span>
</span><span class="line"><span> rg [OPTIONS] [-e PATTERN ...] [-f PATTERNFILE ...] [PATH ...]</span>
</span><span class="line"><span> rg [OPTIONS] --files [PATH ...]</span>
</span><span class="line"><span> rg [OPTIONS] --type-list</span>
</span><span class="line"><span> command | rg [OPTIONS] PATTERN</span>
</span><span class="line"><span></span>
</span><span class="line"><span>ARGS:</span>
</span><span class="line"><span> <PATTERN> A regular expression used for searching.</span>
</span><span class="line"><span> <PATH>... A file or directory to search.</span>
</span><span class="line"><span></span>
</span><span class="line"><span>OPTIONS:</span>
</span><span class="line"><span> -A, --after-context <NUM> Show NUM lines after each match.</span>
</span><span class="line"><span> --auto-hybrid-regex Dynamically use PCRE2 if necessary.</span>
</span><span class="line"><span> -B, --before-context <NUM> Show NUM lines before each match.</span>
</span><span class="line"><span> --binary Search binary files.</span>
</span><span class="line"><span> --block-buffered Force block buffering.</span>
</span><span class="line"><span> -b, --byte-offset Print the 0-based byte offset for each matching line.</span>
</span><span class="line"><span> -s, --case-sensitive Search case sensitively (default).</span>
</span><span class="line"><span> --color <WHEN> Controls when to use color.</span>
</span><span class="line"><span> --colors <COLOR_SPEC>... Configure color settings and styles.</span>
</span><span class="line"><span> --column Show column numbers.</span>
</span><span class="line"><span> -C, --context <NUM> Show NUM lines before and after each match.</span>
</span><span class="line"><span> --context-separator <SEPARATOR> Set the context separator string.</span>
</span><span class="line"><span> -c, --count Only show the count of matching lines for each file.</span>
</span><span class="line"><span> --count-matches Only show the count of individual matches for each file.</span>
</span><span class="line"><span> --crlf Support CRLF line terminators (useful on Windows).</span>
</span><span class="line"><span> --debug Show debug messages.</span>
</span><span class="line"><span> --dfa-size-limit <NUM+SUFFIX?> The upper size limit of the regex DFA.</span>
</span><span class="line"><span> -E, --encoding <ENCODING> Specify the text encoding of files to search.</span>
</span><span class="line"><span> --engine <ENGINE> Specify which regexp engine to use. [default: default]</span>
</span><span class="line"><span> -f, --file <PATTERNFILE>... Search for patterns from the given file.</span>
</span><span class="line"><span> --files Print each file that would be searched.</span>
</span><span class="line"><span> -l, --files-with-matches Only print the paths with at least one match.</span>
</span><span class="line"><span> --files-without-match Only print the paths that contain zero matches.</span>
</span><span class="line"><span> -F, --fixed-strings Treat the pattern as a literal string.</span>
</span><span class="line"><span> -L, --follow Follow symbolic links.</span>
</span><span class="line"><span> -g, --glob <GLOB>... Include or exclude files.</span>
</span><span class="line"><span> --glob-case-insensitive Process all glob patterns case insensitively.</span>
</span><span class="line"><span> -h, --help Prints help information. Use --help for more details.</span>
</span><span class="line"><span> --heading Print matches grouped by each file.</span>
</span><span class="line"><span> --hidden Search hidden files and directories.</span>
</span><span class="line"><span> --iglob <GLOB>... Include or exclude files case insensitively.</span>
</span><span class="line"><span> -i, --ignore-case Case insensitive search.</span>
</span><span class="line"><span> --ignore-file <PATH>... Specify additional ignore files.</span>
</span><span class="line"><span> --ignore-file-case-insensitive Process ignore files case insensitively.</span>
</span><span class="line"><span> --include-zero Include files with zero matches in summary</span>
</span><span class="line"><span> -v, --invert-match Invert matching.</span>
</span><span class="line"><span> --json Show search results in a JSON Lines format.</span>
</span><span class="line"><span> --line-buffered Force line buffering.</span>
</span><span class="line"><span> -n, --line-number Show line numbers.</span>
</span><span class="line"><span> -x, --line-regexp Only show matches surrounded by line boundaries.</span>
</span><span class="line"><span> -M, --max-columns <NUM> Don't print lines longer than this limit.</span>
</span><span class="line"><span> --max-columns-preview Print a preview for lines exceeding the limit.</span>
</span><span class="line"><span> -m, --max-count <NUM> Limit the number of matches.</span>
</span><span class="line"><span> --max-depth <NUM> Descend at most NUM directories.</span>
</span><span class="line"><span> --max-filesize <NUM+SUFFIX?> Ignore files larger than NUM in size.</span>
</span><span class="line"><span> --mmap Search using memory maps when possible.</span>
</span><span class="line"><span> -U, --multiline Enable matching across multiple lines.</span>
</span><span class="line"><span> --multiline-dotall Make '.' match new lines when multiline is enabled.</span>
</span><span class="line"><span> --no-config Never read configuration files.</span>
</span><span class="line"><span> -I, --no-filename Never print the file path with the matched lines.</span>
</span><span class="line"><span> --no-heading Don't group matches by each file.</span>
</span><span class="line"><span> --no-ignore Don't respect ignore files.</span>
</span><span class="line"><span> --no-ignore-dot Don't respect .ignore files.</span>
</span><span class="line"><span> --no-ignore-exclude Don't respect local exclusion files.</span>
</span><span class="line"><span> --no-ignore-files Don't respect --ignore-file arguments.</span>
</span><span class="line"><span> --no-ignore-global Don't respect global ignore files.</span>
</span><span class="line"><span> --no-ignore-messages Suppress gitignore parse error messages.</span>
</span><span class="line"><span> --no-ignore-parent Don't respect ignore files in parent directories.</span>
</span><span class="line"><span> --no-ignore-vcs Don't respect VCS ignore files.</span>
</span><span class="line"><span> -N, --no-line-number Suppress line numbers.</span>
</span><span class="line"><span> --no-messages Suppress some error messages.</span>
</span><span class="line"><span> --no-mmap Never use memory maps.</span>
</span><span class="line"><span> --no-pcre2-unicode Disable Unicode mode for PCRE2 matching.</span>
</span><span class="line"><span> --no-require-git Do not require a git repository to use gitignores.</span>
</span><span class="line"><span> --no-unicode Disable Unicode mode.</span>
</span><span class="line"><span> -0, --null Print a NUL byte after file paths.</span>
</span><span class="line"><span> --null-data Use NUL as a line terminator instead of \n.</span>
</span><span class="line"><span> --one-file-system Do not descend into directories on other file systems.</span>
</span><span class="line"><span> -o, --only-matching Print only matches parts of a line.</span>
</span><span class="line"><span> --passthru Print both matching and non-matching lines.</span>
</span><span class="line"><span> --path-separator <SEPARATOR> Set the path separator.</span>
</span><span class="line"><span> -P, --pcre2 Enable PCRE2 matching.</span>
</span><span class="line"><span> --pcre2-version Print the version of PCRE2 that ripgrep uses.</span>
</span><span class="line"><span> --pre <COMMAND> search outputs of COMMAND FILE for each FILE</span>
</span><span class="line"><span> --pre-glob <GLOB>... Include or exclude files from a preprocessing command.</span>
</span><span class="line"><span> -p, --pretty Alias for --color always --heading --line-number.</span>
</span><span class="line"><span> -q, --quiet Do not print anything to stdout.</span>
</span><span class="line"><span> --regex-size-limit <NUM+SUFFIX?> The upper size limit of the compiled regex.</span>
</span><span class="line"><span> -e, --regexp <PATTERN>... A pattern to search for.</span>
</span><span class="line"><span> -r, --replace <REPLACEMENT_TEXT> Replace matches with the given text.</span>
</span><span class="line"><span> -z, --search-zip Search in compressed files.</span>
</span><span class="line"><span> -S, --smart-case Smart case search.</span>
</span><span class="line"><span> --sort <SORTBY> Sort results in ascending order. Implies --threads=1.</span>
</span><span class="line"><span> --sortr <SORTBY> Sort results in descending order. Implies --threads=1.</span>
</span><span class="line"><span> --stats Print statistics about this ripgrep search.</span>
</span><span class="line"><span> -a, --text Search binary files as if they were text.</span>
</span><span class="line"><span> -j, --threads <NUM> The approximate number of threads to use.</span>
</span><span class="line"><span> --trim Trim prefixed whitespace from matches.</span>
</span><span class="line"><span> -t, --type <TYPE>... Only search files matching TYPE.</span>
</span><span class="line"><span> --type-add <TYPE_SPEC>... Add a new glob for a file type.</span>
</span><span class="line"><span> --type-clear <TYPE>... Clear globs for a file type.</span>
</span><span class="line"><span> --type-list Show all supported file types.</span>
</span><span class="line"><span> -T, --type-not <TYPE>... Do not search files matching TYPE.</span>
</span><span class="line"><span> -u, --unrestricted Reduce the level of "smart" searching.</span>
</span><span class="line"><span> -V, --version Prints version information</span>
</span><span class="line"><span> --vimgrep Show results in vim compatible format.</span>
</span><span class="line"><span> -H, --with-filename Print the file path with the matched lines.</span>
</span><span class="line"><span> -w, --word-regexp Only show matches surrounded by word boundaries.</span></span></code></pre>urn:uuid:30b233ee-3837-4073-acf1-868bfe8796edConst Assertions in Literal Expressions in TypeScript2019-12-15T00:00:00.000Z2020-11-29T00:00:00.000ZWith TypeScript 3.4, const assertions were added to the language. A const assertion is a special kind of type assertion in which the const keyword is used instead of a type name.<p>With TypeScript 3.4, <code>const</code> assertions were added to the language. A <code>const</code> assertion is a special kind of type assertion in which the <code>const</code> keyword is used instead of a type name. In this post, I'll explain how <code>const</code> assertions work and why we might want to use them.</p>
<h2 id="motivation-for-const-assertions"><a class="heading-anchor" href="#motivation-for-const-assertions">#</a>Motivation for <code>const</code> Assertions</h2>
<p>Let's say we've written the following <code>fetchJSON</code> function. It accepts a URL and an HTTP request method, uses the browser's <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a> to make a GET or POST request to that URL, and deserializes the response as JSON:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">function</span><span style="color:#4078F2"> fetchJSON</span><span style="color:#383A42">(url</span><span style="color:#0184BC">:</span><span style="color:#0184BC"> string</span><span style="color:#383A42">, method</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "GET"</span><span style="color:#0184BC"> |</span><span style="color:#50A14F"> "POST"</span><span style="color:#383A42">) {</span>
</span><span class="line"><span style="color:#A626A4"> return</span><span style="color:#4078F2"> fetch</span><span style="color:#383A42">(url, { method }).</span><span style="color:#4078F2">then</span><span style="color:#383A42">(response </span><span style="color:#A626A4">=></span><span style="color:#383A42"> response.</span><span style="color:#4078F2">json</span><span style="color:#383A42">());</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>We can call this function and pass an arbitrary URL to the <code>url</code> param and the string <code>"GET"</code> to the <code>method</code> param. Note that we're using two <strong>string literals</strong> here:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// OK, no type error</span>
</span><span class="line"><span style="color:#4078F2">fetchJSON</span><span style="color:#383A42">(</span><span style="color:#50A14F">"https://example.com/"</span><span style="color:#383A42">, </span><span style="color:#50A14F">"GET"</span><span style="color:#383A42">).</span><span style="color:#4078F2">then</span><span style="color:#383A42">(data </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> // ...</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>To verify whether this function call is type-correct, TypeScript will check the types of all arguments of the function call against the parameter types defined in the function declaration. In this case, the types of both arguments are assignable to the parameter types, and therefore this function call type-checks correctly.</p>
<p>Let's now do a little bit of refactoring. The HTTP specification defines various additional <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods">request methods</a> such as DELETE, HEAD, PUT, and others. We can define an <code>HTTPRequestMethod</code> enum-style mapping object and list the various request methods:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> HTTPRequestMethod</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> CONNECT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "CONNECT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> DELETE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "DELETE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> GET</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> HEAD</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "HEAD"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> OPTIONS</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "OPTIONS"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PATCH</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PATCH"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> POST</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "POST"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PUT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PUT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> TRACE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "TRACE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>Now we can replace the string literal <code>"GET"</code> in our <code>fetchJSON</code> function call by <code>HTTPRequestMethod.GET</code>:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#4078F2">fetchJSON</span><span style="color:#383A42">(</span><span style="color:#50A14F">"https://example.com/"</span><span style="color:#383A42">, HTTPRequestMethod.</span><span style="color:#986801">GET</span><span style="color:#383A42">).</span><span style="color:#4078F2">then</span><span style="color:#383A42">(data </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> // ...</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>But now, TypeScript produces a type error! The type checker points out that the type of <code>HTTPRequestMethod.GET</code> is not assignable to the type of the <code>method</code> param:</p>
<pre><code><span class="line"><span>// Error: Argument of type 'string' is not assignable</span>
</span><span class="line"><span>// to parameter of type '"GET" | "POST"'.</span></span></code></pre><p>Why is that? <code>HTTPRequestMethod.GET</code> evaluates to the string <code>"GET"</code>, the same value that we passed as an argument before. What's the difference between the types of the property <code>HTTPRequestMethod.GET</code> and the string literal <code>"GET"</code>? To answer that question, we have to understand how <strong>string literal types</strong> work and how TypeScript performs <strong>literal type widening</strong>.</p>
<h2 id="string-literal-types"><a class="heading-anchor" href="#string-literal-types">#</a>String Literal Types</h2>
<p>Let's look at the type of the value <code>"GET"</code> when we assign it to a variable declared using the <code>const</code> keyword:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: "GET"</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> httpRequestMethod</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42">;</span></span></code></pre><p>TypeScript infers the type <code>"GET"</code> for our <code>httpRequestMethod</code> variable. <code>"GET"</code> is what's called a <a href="/blog/string-literal-types-in-typescript">string literal type</a>. Each literal type describes precisely one value, e.g. a specific string, number, boolean value, or enum member. In our case, we're dealing with the string value <code>"GET"</code>, so our literal type is the string literal type <code>"GET"</code>.</p>
<p>Notice that we've declared the <code>httpRequestMethod</code> variable using the <code>const</code> keyword. Therefore, we know that it's impossible to reassign the variable later; it'll always hold the value <code>"GET"</code>. TypeScript understands that and automatically infers the string literal type <code>"GET"</code> to represent this piece of information in the type system.</p>
<h2 id="literal-type-widening"><a class="heading-anchor" href="#literal-type-widening">#</a>Literal Type Widening</h2>
<p>Let's now see what happens if we use the <code>let</code> keyword (instead of <code>const</code>) to declare the <code>httpRequestMethod</code> variable:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: string</span>
</span><span class="line"><span style="color:#A626A4">let</span><span style="color:#383A42"> httpRequestMethod </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42">;</span></span></code></pre><p>TypeScript now performs what's known as <a href="/blog/literal-type-widening-in-typescript">literal type widening</a>. The <code>httpRequestMethod</code> variable is inferred to have type <code>string</code>. We're initializing <code>httpRequestMethod</code> with the string <code>"GET"</code>, but since the variable is declared using the <code>let</code> keyword, we can assign another value to it later:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: string</span>
</span><span class="line"><span style="color:#A626A4">let</span><span style="color:#383A42"> httpRequestMethod </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42">;</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// OK, no type error</span>
</span><span class="line"><span style="color:#383A42">httpRequestMethod </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "POST"</span><span style="color:#383A42">;</span></span></code></pre><p>The later assignment of the value <code>"POST"</code> is type-correct since <code>httpRequestMethod</code> has type <code>string</code>. TypeScript inferred the type <code>string</code> because we most likely want to change the value of a variable declared using the <code>let</code> keyword later on. If we didn't want to reassign the variable, we should've used the <code>const</code> keyword instead.</p>
<p>Let's now look at our enum-style mapping object:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> HTTPRequestMethod</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> CONNECT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "CONNECT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> DELETE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "DELETE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> GET</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> HEAD</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "HEAD"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> OPTIONS</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "OPTIONS"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PATCH</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PATCH"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> POST</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "POST"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PUT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PUT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> TRACE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "TRACE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>What type does <code>HTTPRequestMethod.GET</code> have? Let's find out:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: string</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> httpRequestMethod</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> HTTPRequestMethod.</span><span style="color:#986801">GET</span><span style="color:#383A42">;</span></span></code></pre><p>TypeScript infers the type <code>string</code> for our <code>httpRequestMethod</code> variable. This is because we're initializing the variable with the value <code>HTTPRequestMethod.GET</code> (which has type <code>string</code>), so type <code>string</code> is inferred.</p>
<p>So why does <code>HTTPRequestMethod.GET</code> have type <code>string</code> and not type <code>"GET"</code>? We're initializing the <code>GET</code> property with the string literal <code>"GET"</code>, and the <code>HTTPRequestMethod</code> object itself is defined using the <code>const</code> keyword. Shouldn't the resulting type be the string literal type <code>"GET"</code>?</p>
<p>The reason that TypeScript infers type <code>string</code> for <code>HTTPRequestMethod.GET</code> (and all the other properties) is that we could assign another value to any of the properties later on. To us, this object with its ALL_UPPERCASE property names looks like an enum which defines string constants that won't change over time. However, to TypeScript this is just a regular object with a few properties that happen to be initialized with string values.</p>
<p>The following example makes it a bit more obvious why TypeScript shouldn't infer a string literal type for object properties initialized with a string literal:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: { name: string, jobTitle: string }</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> person</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> name</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "Marius Schulz"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> jobTitle</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "Software Engineer"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">};</span>
</span><span class="line">
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// OK, no type error</span>
</span><span class="line"><span style="color:#383A42">person.</span><span style="color:#E45649">jobTitle</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "Front End Engineer"</span><span style="color:#383A42">;</span></span></code></pre><p>If the <code>jobTitle</code> property were inferred to have type <code>"Software Engineer"</code>, it would be a type error if we tried to assign any string other than <code>"Software Engineer"</code> later on. Our assignment of <code>"Front End Engineer"</code> would not be type-correct. Object properties are mutable by default, so we wouldn't want TypeScript to infer a type which restricts us from performing perfectly valid mutations.</p>
<p>So how do we make the usage of our <code>HTTPRequestMethod.GET</code> property in the function call type-check correctly? We need to understand <strong>non-widening literal types</strong> first.</p>
<h2 id="non-widening-literal-types"><a class="heading-anchor" href="#non-widening-literal-types">#</a>Non-Widening Literal Types</h2>
<p>TypeScript has a special kind of literal type that's known as a <a href="/blog/literal-type-widening-in-typescript#non-widening-literal-types">non-widening literal type</a>. As the name suggests, non-widening literal types will not be widened to a more generic type. For example, the non-widening string literal type <code>"GET"</code> will not be widened to <code>string</code> in cases where type widening would normally occur.</p>
<p>We can make the properties of our <code>HTTPRequestMethod</code> object receive a non-widening literal type by applying a type assertion of the corresponding string literal type to every property value:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> HTTPRequestMethod</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> CONNECT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "CONNECT"</span><span style="color:#383A42"> as </span><span style="color:#50A14F">"CONNECT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> DELETE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "DELETE"</span><span style="color:#383A42"> as </span><span style="color:#50A14F">"DELETE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> GET</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42"> as </span><span style="color:#50A14F">"GET"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> HEAD</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "HEAD"</span><span style="color:#383A42"> as </span><span style="color:#50A14F">"HEAD"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> OPTIONS</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "OPTIONS"</span><span style="color:#383A42"> as </span><span style="color:#50A14F">"OPTIONS"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PATCH</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PATCH"</span><span style="color:#383A42"> as </span><span style="color:#50A14F">"PATCH"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> POST</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "POST"</span><span style="color:#383A42"> as </span><span style="color:#50A14F">"POST"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PUT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PUT"</span><span style="color:#383A42"> as </span><span style="color:#50A14F">"PUT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> TRACE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "TRACE"</span><span style="color:#383A42"> as </span><span style="color:#50A14F">"TRACE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>Now, let's check the type of <code>HTTPRequestMethod.GET</code> again:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: "GET"</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> httpRequestMethod</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> HTTPRequestMethod.</span><span style="color:#986801">GET</span><span style="color:#383A42">;</span></span></code></pre><p>And indeed, now the <code>httpRequestMethod</code> variable has type <code>"GET"</code> rather than type <code>string</code>. The type of <code>HTTPRequestMethod.GET</code> (which is <code>"GET"</code>) is assignable to the type of the <code>method</code> parameter (which is <code>"GET" | "POST"</code>), and therefore the <code>fetchJSON</code> function call will now type-check correctly:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// OK, no type error</span>
</span><span class="line"><span style="color:#4078F2">fetchJSON</span><span style="color:#383A42">(</span><span style="color:#50A14F">"https://example.com/"</span><span style="color:#383A42">, HTTPRequestMethod.</span><span style="color:#986801">GET</span><span style="color:#383A42">).</span><span style="color:#4078F2">then</span><span style="color:#383A42">(data </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> // ...</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>This is great news, but take a look at the number of type assertions we had to write to get to this point. That is a lot of noise! Every key/value pair now contains the name of the HTTP request method three times. Can we simplify this definition? Using TypeScript's <code>const</code> assertions feature, we most certainly can!</p>
<h2 id="const-assertions-for-literal-expressions"><a class="heading-anchor" href="#const-assertions-for-literal-expressions">#</a><code>const</code> Assertions for Literal Expressions</h2>
<p>Our <code>HTTPRequestMethod</code> variable is initialized with a <strong>literal expression</strong> which is an <strong>object literal</strong> with several properties, all of which are initialized with <strong>string literals</strong>. As of TypeScript 3.4, we can apply a <code>const</code> assertion to a literal expression:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> HTTPRequestMethod</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> CONNECT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "CONNECT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> DELETE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "DELETE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> GET</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> HEAD</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "HEAD"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> OPTIONS</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "OPTIONS"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PATCH</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PATCH"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> POST</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "POST"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PUT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PUT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> TRACE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "TRACE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">} as </span><span style="color:#A626A4">const</span><span style="color:#383A42">;</span></span></code></pre><p>A <code>const</code> assertion is a special type assertion that uses the <code>const</code> keyword instead of a specific type name. Using a <code>const</code> assertion on a literal expression has the following effects:</p>
<ol>
<li>No literal types in the literal expression will be <a href="/blog/literal-type-widening-in-typescript">widened</a>.</li>
<li>Object literals will get <a href="/blog/read-only-properties-in-typescript"><code>readonly</code> properties</a>.</li>
<li>Array literals will become <a href="/blog/read-only-array-and-tuple-types-in-typescript"><code>readonly</code> tuples</a>.</li>
</ol>
<p>With the <code>const</code> assertion in place, the above definition of <code>HTTPRequestMethod</code> is equivalent to the following:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> HTTPRequestMethod</span><span style="color:#0184BC">:</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> CONNECT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "CONNECT"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> DELETE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "DELETE"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> GET</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> HEAD</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "HEAD"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> OPTIONS</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "OPTIONS"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> PATCH</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PATCH"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> POST</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "POST"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> PUT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PUT"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> TRACE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "TRACE"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">} </span><span style="color:#0184BC">=</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> CONNECT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "CONNECT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> DELETE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "DELETE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> GET</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> HEAD</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "HEAD"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> OPTIONS</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "OPTIONS"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PATCH</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PATCH"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> POST</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "POST"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PUT</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "PUT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> TRACE</span><span style="color:#0184BC">:</span><span style="color:#50A14F"> "TRACE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>We wouldn't want to have to write this definition by hand. It's verbose and contains a lot of repetition; notice that every HTTP request method is spelled out four times. The <code>const</code> assertion <code>as const</code>, on the other hand, is very succinct and the only bit of TypeScript-specific syntax in the entire example.</p>
<p>Also, observe that every property is now typed as <code>readonly</code>. If we try to assign a value to a <a href="/blog/read-only-properties-in-typescript">read-only property</a>, TypeScript will product a type error:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Error: Cannot assign to 'GET'</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic">// because it is a read-only property.</span>
</span><span class="line"><span style="color:#383A42">HTTPRequestMethod.</span><span style="color:#986801">GET</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "..."</span><span style="color:#383A42">;</span></span></code></pre><p>With the <code>const</code> assertion, we've given our <code>HTTPRequestMethod</code> object enum-like characteristics. But what about proper TypeScript enums?</p>
<h2 id="using-typescript-enums"><a class="heading-anchor" href="#using-typescript-enums">#</a>Using TypeScript Enums</h2>
<p>Another possible solution would've been to use a <a href="https://www.typescriptlang.org/docs/handbook/enums.html">TypeScript enum</a> instead of a plain object literal. We could've defined <code>HTTPRequestMethod</code> using the <code>enum</code> keyword like this:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">enum</span><span style="color:#C18401"> HTTPRequestMethod</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> CONNECT</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "CONNECT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> DELETE</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "DELETE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> GET</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> HEAD</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "HEAD"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> OPTIONS</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "OPTIONS"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PATCH</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "PATCH"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> POST</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "POST"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> PUT</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "PUT"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> TRACE</span><span style="color:#0184BC"> =</span><span style="color:#50A14F"> "TRACE"</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">}</span></span></code></pre><p>TypeScript enums are meant to describe named constants, which is why their members are always read-only. Members of a <a href="/blog/string-enums-in-typescript">string enum</a> have a string literal type:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: "GET"</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> httpRequestMethod</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> HTTPRequestMethod.</span><span style="color:#986801">GET</span><span style="color:#383A42">;</span></span></code></pre><p>This means our function call will type-check when we pass <code>HTTPRequestMethod.GET</code> as an argument for the <code>method</code> parameter:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// OK, no type error</span>
</span><span class="line"><span style="color:#4078F2">fetchJSON</span><span style="color:#383A42">(</span><span style="color:#50A14F">"https://example.com/"</span><span style="color:#383A42">, HTTPRequestMethod.</span><span style="color:#986801">GET</span><span style="color:#383A42">).</span><span style="color:#4078F2">then</span><span style="color:#383A42">(data </span><span style="color:#A626A4">=></span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A0A1A7;font-style:italic"> // ...</span>
</span><span class="line"><span style="color:#383A42">});</span></span></code></pre><p>However, some developers don't like to use TypeScript enums in their code because the <code>enum</code> syntax is not valid JavaScript on its own. The TypeScript compiler will emit the following JavaScript code for our <code>HTTPRequestMethod</code> enum defined above:</p>
<pre><code class="language-js"><span class="line"><span style="color:#A626A4">var</span><span style="color:#383A42"> HTTPRequestMethod;</span>
</span><span class="line"><span style="color:#383A42">(</span><span style="color:#A626A4">function</span><span style="color:#383A42"> (HTTPRequestMethod) {</span>
</span><span class="line"><span style="color:#383A42"> HTTPRequestMethod[</span><span style="color:#50A14F">"CONNECT"</span><span style="color:#383A42">] </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "CONNECT"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> HTTPRequestMethod[</span><span style="color:#50A14F">"DELETE"</span><span style="color:#383A42">] </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "DELETE"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> HTTPRequestMethod[</span><span style="color:#50A14F">"GET"</span><span style="color:#383A42">] </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "GET"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> HTTPRequestMethod[</span><span style="color:#50A14F">"HEAD"</span><span style="color:#383A42">] </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "HEAD"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> HTTPRequestMethod[</span><span style="color:#50A14F">"OPTIONS"</span><span style="color:#383A42">] </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "OPTIONS"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> HTTPRequestMethod[</span><span style="color:#50A14F">"PATCH"</span><span style="color:#383A42">] </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "PATCH"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> HTTPRequestMethod[</span><span style="color:#50A14F">"POST"</span><span style="color:#383A42">] </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "POST"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> HTTPRequestMethod[</span><span style="color:#50A14F">"PUT"</span><span style="color:#383A42">] </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "PUT"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42"> HTTPRequestMethod[</span><span style="color:#50A14F">"TRACE"</span><span style="color:#383A42">] </span><span style="color:#0184BC">=</span><span style="color:#50A14F"> "TRACE"</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">})(HTTPRequestMethod </span><span style="color:#0184BC">||</span><span style="color:#383A42"> (HTTPRequestMethod </span><span style="color:#0184BC">=</span><span style="color:#383A42"> {}));</span></span></code></pre><p>It's entirely up to you to decide whether you want to use plain object literals or proper TypeScript enums. If you want to stay as close to JavaScript as possible and only use TypeScript for type annotations, you can stick with plain object literals and <code>const</code> assertions. If you don't mind using non-standard syntax for defining enums and you like the brevity, TypeScript enums could be a good choice.</p>
<h2 id="const-assertions-for-other-types"><a class="heading-anchor" href="#const-assertions-for-other-types">#</a><code>const</code> Assertions for Other Types</h2>
<p>You can apply a <code>const</code> assertion to …</p>
<ul>
<li>string literals,</li>
<li>numeric literals,</li>
<li>boolean literals,</li>
<li>array literals, and</li>
<li>object literals.</li>
</ul>
<p>For example, you could define an <code>ORIGIN</code> variable describing the origin in 2-dimensional space like this:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> ORIGIN</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> x</span><span style="color:#0184BC">:</span><span style="color:#986801"> 0</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> y</span><span style="color:#0184BC">:</span><span style="color:#986801"> 0</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">} as </span><span style="color:#A626A4">const</span><span style="color:#383A42">;</span></span></code></pre><p>This is equivalent to (and much more succinct than) the following declaration:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> ORIGIN</span><span style="color:#0184BC">:</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> x</span><span style="color:#0184BC">:</span><span style="color:#986801"> 0</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#A626A4"> readonly</span><span style="color:#383A42"> y</span><span style="color:#0184BC">:</span><span style="color:#986801"> 0</span><span style="color:#383A42">;</span>
</span><span class="line"><span style="color:#383A42">} </span><span style="color:#0184BC">=</span><span style="color:#383A42"> {</span>
</span><span class="line"><span style="color:#E45649"> x</span><span style="color:#0184BC">:</span><span style="color:#986801"> 0</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#E45649"> y</span><span style="color:#0184BC">:</span><span style="color:#986801"> 0</span><span style="color:#383A42">,</span>
</span><span class="line"><span style="color:#383A42">};</span></span></code></pre><p>Alternatively, you could've modeled the representation of a point as a tuple of the X and Y coordinates:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: readonly [0, 0]</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> ORIGIN</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">0</span><span style="color:#383A42">, </span><span style="color:#986801">0</span><span style="color:#383A42">] as </span><span style="color:#A626A4">const</span><span style="color:#383A42">;</span></span></code></pre><p>Because of the <code>const</code> assertion, <code>ORIGIN</code> is typed as <code>readonly [0, 0]</code>. Without the assertion, <code>ORIGIN</code> would've been inferred to have type <code>number[]</code> instead:</p>
<pre><code class="language-ts"><span class="line"><span style="color:#A0A1A7;font-style:italic">// Type: number[]</span>
</span><span class="line"><span style="color:#A626A4">const</span><span style="color:#986801"> ORIGIN</span><span style="color:#0184BC"> =</span><span style="color:#383A42"> [</span><span style="color:#986801">0</span><span style="color:#383A42">, </span><span style="color:#986801">0</span><span style="color:#383A42">];</span></span></code></pre>