JSON Feed Validator

Check whether your feed is valid. For more information about JSON Feed, see the specification.

{
  "version": "https://jsonfeed.org/version/1",
  "title": "Andrew Burgess | shaky.sh",
  "home_page_url": "https://shaky.sh",
  "feed_url": "https://shaky.sh/feed.json",
  "description": "Blog Posts and other thoughts, mostly about build web software. By Andrew Burgess.",
  "icon": "https://shaky.sh/assets/avatar.webp",
  "favicon": "https://shaky.sh/assets/shaky.png",
  "author": {
    "name": "Andrew Burgess",
    "url": "https://shaky.sh",
    "avatar": "https://shaky.sh/assets/avatar.webp"
  },
  "items": [
    {
      "id": "https://shaky.sh/simple-dotfiles/",
      "url": "https://shaky.sh/simple-dotfiles/",
      "title": "Simple Dotfiles",
      "content_html": "<p>For as long as I can remember, tweaking my dotfiles repo has been my favourite way to procrastinate. When I was in school, when I was freelancing, and now at my corporate job, it's a constant in my programming practice.</p> <p>So, it makes sense that, while trying to coming up with better things to write about, I write about dotfiles.</p> <h2 id=\"the-structure\" tabindex=\"-1\">The Structure</h2> <p>At a high level, <a href=\"https://github.com/andrew8088/dotfiles\">my dotfiles repo</a> has one folder for each application that I want to configure:</p> <pre class=\"language-text\"><code class=\"language-text\"><span class=\"highlight-line\">~/bin/dotfiles</span> <span class=\"highlight-line\">❯ tree -L 1</span> <span class=\"highlight-line\">.</span> <span class=\"highlight-line\">├── README.md</span> <span class=\"highlight-line\">├── alacritty</span> <span class=\"highlight-line\">├── brew</span> <span class=\"highlight-line\">├── git</span> <span class=\"highlight-line\">├── mutt</span> <span class=\"highlight-line\">├── nvim</span> <span class=\"highlight-line\">├── scripts</span> <span class=\"highlight-line\">├── tmux</span> <span class=\"highlight-line\">├── vim</span> <span class=\"highlight-line\">└── zsh</span></code></pre> <p>The one extra directory there is <code>scripts</code>, home to the install scripts.</p> <p>Within each of these application directories live two<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">1</a></sup> types of files:</p> <ul> <li>the actual config files (duh)</li> <li>a <code>links.prop</code> file</li> </ul> <h2 id=\"the-configuration\" tabindex=\"-1\">The Configuration</h2> <p>The config files aren't much different from any other dotfiles repo you'll see out there (and honestly, there are better ones to look at). What I'm most pleased with in my current iteration, though, is the file naming pattern. In the past, I'd use file names like <code>vimrc</code> and <code>zshrc</code> ... which is pretty common, right? My gripe though: most editors don't give you syntax highlighting by default, when your file has no extension. So now I'm using file names like <code>rc.vim</code> and <code>rc.zsh</code>, and get the syntax highlighting. Small change, big difference.</p> <p>As you can see, there's not too many apps I'm configuring. The three I've invested the most time in are definitely</p> <ul> <li>zsh</li> <li>vim / <a href=\"https://neovim.io/\">neovim</a></li> <li><a href=\"https://github.com/alacritty/alacritty\">alacritty</a></li> </ul> <p>I haven't used mutt in a few years, so it's likely a bit stale. The tmux config is good, but I've started using separate terminal windows more recently.</p> <h2 id=\"the-links\" tabindex=\"-1\">The Links</h2> <p>I think we'd all agree: one of the main idea of a <code>dotfiles</code> repo is symlinking all your files into place, so they remain under version control while they do their job from (usually) your home directory.</p> <p>To that end, we have the <code>links.prop</code> files, one per app dir. Looks something like this:</p> <pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"highlight-line\"><span class=\"token variable\">$DOTFILES</span>/vim/rc.vim<span class=\"token operator\">=</span><span class=\"token environment constant\">$HOME</span>/.vimrc</span> <span class=\"highlight-line\"><span class=\"token variable\">$DOTFILES</span>/vim<span class=\"token operator\">=</span><span class=\"token environment constant\">$HOME</span>/.vim</span></code></pre> <p>On the left, we have the source. On the right, we have the destination. This is just a simple way to codify the symlinks that need to be created to &quot;install&quot; these configs. The <code>bootstrap.sh</code> script<sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">2</a></sup> file will replace any environment variables in these lines, and then create the symlinks.</p> <h2 id=\"the-local-stuff\" tabindex=\"-1\">The Local Stuff</h2> <p>The <code>bootstrap.sh</code> script also creates a file called <code>~/.env.sh</code>. By default, it includes a single line:</p> <pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"highlight-line\"><span class=\"token builtin class-name\">export</span> <span class=\"token assign-left variable\">DOTFILES</span><span class=\"token operator\">=</span>/path/to/dotfiles</span></code></pre> <p>This file is for any machine-specific configuration. Need to include API keys or other secrets as env vars, but don't want to commit them? Have extra paths or tools that you need to configure for a work machine? Yes and yes, as a matter of fact.</p> <p>Then, we source <code>~/.env.sh</code> in the &quot;root&quot; <code>~/.zshrc</code>. Actually, there's another trick here that I use for loading several config files that may not always exist. It's a little shell function called <code>source_if_exists</code>:</p> <pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"highlight-line\"><span class=\"token function-name function\">source_if_exists</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">if</span> <span class=\"token builtin class-name\">test</span> <span class=\"token parameter variable\">-r</span> <span class=\"token string\">\"<span class=\"token variable\">$1</span>\"</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">then</span></span> <span class=\"highlight-line\">        <span class=\"token builtin class-name\">source</span> <span class=\"token string\">\"<span class=\"token variable\">$1</span>\"</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">fi</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>If the file exists, and is readable, then we'll source it! Another tiny tool, but it gives me a clear set of lines, like this:</p> <pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"highlight-line\">source_if_exists <span class=\"token variable\">$DOTFILES</span>/zsh/aliases.zsh</span> <span class=\"highlight-line\">source_if_exists <span class=\"token variable\">$DOTFILES</span>/zsh/history.zsh</span> <span class=\"highlight-line\">source_if_exists <span class=\"token variable\">$DOTFILES</span>/zsh/p10k.zsh</span> <span class=\"highlight-line\">source_if_exists <span class=\"token environment constant\">$HOME</span>/.env.sh</span> <span class=\"highlight-line\">source_if_exists <span class=\"token environment constant\">$HOME</span>/bin/z.sh</span> <span class=\"highlight-line\">source_if_exists <span class=\"token environment constant\">$HOME</span>/.fzf.zsh</span></code></pre> <p>Ugh, so clean.</p> <h2 id=\"the-next-steps\" tabindex=\"-1\">The Next Steps</h2> <p>The nature of dotfiles is to always be evolving. Next tax season, here's my shortlist for next features:</p> <ul> <li> <p><strong>Add a solid install script for all tools and dependencies that I regularly use</strong>. I have a weak version of this right now, but it's incomplete. There's a <a href=\"https://github.com/Homebrew/homebrew-bundle\">thing called Homebrew Bundle</a> that looks like a really solid start.</p> </li> <li> <p><strong>Configure MacOS itself</strong>. You can set a lot of <a href=\"https://github.com/mathiasbynens/dotfiles/blob/main/.macos\">macOS preferences from the command line</a>. This feels like a no-brainer for me.</p> </li> <li> <p><strong>Support Linux</strong>. The base config I have here definitely works on the linux distros I've tried (so, Ubuntu ... and Raspbian, I guess). But once I have my whole env installation set up for macOS, it'd really lower the barrier-to-entry to have that for, say, Archlinux.</p> </li> </ul> <hr class=\"footnotes-sep\"><section class=\"footnotes\"><ol class=\"footnotes-list\"><li id=\"fn1\" class=\"footnote-item\"><p>Some apps also have an <code>install.sh</code> file ... idea in progress. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p> </li> <li id=\"fn2\" class=\"footnote-item\"><p>You can find a similar script in <a href=\"https://github.com/folksgl/.dotfiles/blob/master/bootstrap.sh\">other people's dotfiles</a>, but support for the <code>links.prop</code> is my own addition. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p> </li> </ol> </section> ",
      "content_text": "For as long as I can remember, tweaking my dotfiles repo has been my favourite way to procrastinate. When I was in school, when I was freelancing, and now at my corporate job, it's a constant in my programming practice. So, it makes sense that, while trying to coming up with better things to write about, I write about dotfiles. The Structure At a high level, my dotfiles repo has one folder for each application that I want to configure: ~/bin/dotfiles ❯ tree -L 1 . ├── README.md ├── alacritty ├── brew ├── git ├── mutt ├── nvim ├── scripts ├── tmux ├── vim └── zsh The one extra directory there is scripts, home to the install scripts. Within each of these application directories live two1 types of files:  the actual config files (duh) a links.prop file  The Configuration The config files aren't much different from any other dotfiles repo you'll see out there (and honestly, there are better ones to look at). What I'm most pleased with in my current iteration, though, is the file naming pattern. In the past, I'd use file names like vimrc and zshrc ... which is pretty common, right? My gripe though: most editors don't give you syntax highlighting by default, when your file has no extension. So now I'm using file names like rc.vim and rc.zsh, and get the syntax highlighting. Small change, big difference. As you can see, there's not too many apps I'm configuring. The three I've invested the most time in are definitely  zsh vim / neovim alacritty  I haven't used mutt in a few years, so it's likely a bit stale. The tmux config is good, but I've started using separate terminal windows more recently. The Links I think we'd all agree: one of the main idea of a dotfiles repo is symlinking all your files into place, so they remain under version control while they do their job from (usually) your home directory. To that end, we have the links.prop files, one per app dir. Looks something like this: $DOTFILES/vim/rc.vim=$HOME/.vimrc $DOTFILES/vim=$HOME/.vim On the left, we have the source. On the right, we have the destination. This is just a simple way to codify the symlinks that need to be created to &quot;install&quot; these configs. The bootstrap.sh script2 file will replace any environment variables in these lines, and then create the symlinks. The Local Stuff The bootstrap.sh script also creates a file called ~/.env.sh. By default, it includes a single line: export DOTFILES=/path/to/dotfiles This file is for any machine-specific configuration. Need to include API keys or other secrets as env vars, but don't want to commit them? Have extra paths or tools that you need to configure for a work machine? Yes and yes, as a matter of fact. Then, we source ~/.env.sh in the &quot;root&quot; ~/.zshrc. Actually, there's another trick here that I use for loading several config files that may not always exist. It's a little shell function called source_if_exists: source_if_exists () {     if test -r \"$1\"; then         source \"$1\"     fi } If the file exists, and is readable, then we'll source it! Another tiny tool, but it gives me a clear set of lines, like this: source_if_exists $DOTFILES/zsh/aliases.zsh source_if_exists $DOTFILES/zsh/history.zsh source_if_exists $DOTFILES/zsh/p10k.zsh source_if_exists $HOME/.env.sh source_if_exists $HOME/bin/z.sh source_if_exists $HOME/.fzf.zsh Ugh, so clean. The Next Steps The nature of dotfiles is to always be evolving. Next tax season, here's my shortlist for next features:   Add a solid install script for all tools and dependencies that I regularly use. I have a weak version of this right now, but it's incomplete. There's a thing called Homebrew Bundle that looks like a really solid start.   Configure MacOS itself. You can set a lot of macOS preferences from the command line. This feels like a no-brainer for me.   Support Linux. The base config I have here definitely works on the linux distros I've tried (so, Ubuntu ... and Raspbian, I guess). But once I have my whole env installation set up for macOS, it'd really lower the barrier-to-entry to have that for, say, Archlinux.   Some apps also have an install.sh file ... idea in progress. ↩︎  You can find a similar script in other people's dotfiles, but support for the links.prop is my own addition. ↩︎    ",
      "date_published": "2021-02-18T00:00:00.000Z",
      "tags": [
        "terminal",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/readable-sql-queries-with-with/",
      "url": "https://shaky.sh/readable-sql-queries-with-with/",
      "title": "Readable SQL queries with Common Table Expressions",
      "content_html": "<p>When I'm writing ad hoc SQL queries, I often build them up slowly as I work through the problem at hand; usually, they take the form of several nested <code>SELECT</code> queries. However, that's rarely very readable, not great for sharing with the rest of the team, or for referring back to later. Recently, I've started using <code>WITH</code> queries to clean up my queries.</p> <h2 id=\"an-example\" tabindex=\"-1\">An Example</h2> <p>Let's look at a simple (and not too contrived, I hope) example. Let's say I'm investigating a state change in my users: I want to know how quickly they move from <code>pending</code> to <code>active</code>. If you want to follow along, <a href=\"http://sqlfiddle.com/#!17/420cb/10\">check out the SQL Fiddle</a>.</p> <p>Let's start by finding all active users.</p> <pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"highlight-line\"><span class=\"token keyword\">SELECT</span> <span class=\"token operator\">*</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">FROM</span> users</span> <span class=\"highlight-line\"><span class=\"token keyword\">WHERE</span> state <span class=\"token operator\">=</span> <span class=\"token string\">'active'</span><span class=\"token punctuation\">;</span></span></code></pre> <p>The result:</p> <pre class=\"language-text\"><code class=\"language-text\"><span class=\"highlight-line\">| id |  state | activation_method |                  created_at |</span> <span class=\"highlight-line\">|----|--------|-------------------|-----------------------------|</span> <span class=\"highlight-line\">|  2 | active |             email | 2021-04-01T13:06:22.943296Z |</span> <span class=\"highlight-line\">|  3 | active |              text | 2021-04-06T11:06:22.943296Z |</span> <span class=\"highlight-line\">|  4 | active |              text | 2021-04-02T13:06:22.943296Z |</span> <span class=\"highlight-line\">|  5 | active |             email | 2021-04-03T13:06:22.943296Z |</span></code></pre> <p>Then, let's find <code>user_events</code> for those users:</p> <pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"highlight-line\"><span class=\"token keyword\">SELECT</span> <span class=\"token operator\">*</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">FROM</span> user_events</span> <span class=\"highlight-line\"><span class=\"token keyword\">WHERE</span> user_id <span class=\"token operator\">in</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> id <span class=\"token keyword\">FROM</span> users <span class=\"token keyword\">WHERE</span> state <span class=\"token operator\">=</span> <span class=\"token string\">'active'</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\"><span class=\"token operator\">AND</span> state <span class=\"token operator\">IN</span> <span class=\"token punctuation\">(</span><span class=\"token string\">'pending'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'active'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Now we have a list of events where the state of currently-active users changed.</p> <pre class=\"language-text\"><code class=\"language-text\"><span class=\"highlight-line\">| id | user_id |             action |   state |                  created_at |</span> <span class=\"highlight-line\">|----|---------|--------------------|---------|-----------------------------|</span> <span class=\"highlight-line\">|  2 |       2 | registered-account | pending | 2021-04-01T12:57:36.903034Z |</span> <span class=\"highlight-line\">|  3 |       2 |  activated-account |  active | 2021-04-03T12:57:36.903034Z |</span> <span class=\"highlight-line\">|  4 |       3 | registered-account | pending | 2021-04-06T10:57:36.903034Z |</span> <span class=\"highlight-line\">|  5 |       3 |  activated-account |  active | 2021-04-06T12:57:36.903034Z |</span> <span class=\"highlight-line\">|  6 |       4 | registered-account | pending | 2021-04-02T12:57:36.903034Z |</span> <span class=\"highlight-line\">|  8 |       4 |  activated-account |  active | 2021-04-02T16:57:36.903034Z |</span> <span class=\"highlight-line\">|  7 |       5 | registered-account | pending | 2021-04-04T12:57:36.903034Z |</span> <span class=\"highlight-line\">|  9 |       5 |  activated-account |  active | 2021-04-06T12:57:36.903034Z |</span></code></pre> <p>Let's use a <a href=\"https://www.postgresql.org/docs/current/tutorial-window.html\">window function</a> to find the activation delay. We'll take the difference between registration time and activation time:</p> <pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"highlight-line\"><span class=\"token keyword\">SELECT</span></span> <span class=\"highlight-line\">  user_id<span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  created_at <span class=\"token operator\">-</span> LAG<span class=\"token punctuation\">(</span>created_at<span class=\"token punctuation\">,</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">OVER</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">PARTITION</span> <span class=\"token keyword\">BY</span> user_id <span class=\"token keyword\">ORDER</span> <span class=\"token keyword\">BY</span> created_at<span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> activation_delay</span> <span class=\"highlight-line\"><span class=\"token keyword\">FROM</span> user_events</span> <span class=\"highlight-line\"><span class=\"token keyword\">WHERE</span> user_id <span class=\"token operator\">in</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> id <span class=\"token keyword\">FROM</span> users <span class=\"token keyword\">WHERE</span> state <span class=\"token operator\">=</span> <span class=\"token string\">'active'</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\"><span class=\"token operator\">AND</span> state <span class=\"token operator\">IN</span> <span class=\"token punctuation\">(</span><span class=\"token string\">'pending'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'active'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Nice! Now we can see how long each user took to activate.</p> <pre class=\"language-text\"><code class=\"language-text\"><span class=\"highlight-line\">| user_id |                               activation_delay |</span> <span class=\"highlight-line\">|---------|------------------------------------------------|</span> <span class=\"highlight-line\">|       2 |                                         (null) |</span> <span class=\"highlight-line\">|       2 | 0 years 0 mons 2 days 0 hours 0 mins 0.00 secs |</span> <span class=\"highlight-line\">|       3 |                                         (null) |</span> <span class=\"highlight-line\">|       3 | 0 years 0 mons 0 days 2 hours 0 mins 0.00 secs |</span> <span class=\"highlight-line\">|       4 |                                         (null) |</span> <span class=\"highlight-line\">|       4 | 0 years 0 mons 0 days 4 hours 0 mins 0.00 secs |</span> <span class=\"highlight-line\">|       5 |                                         (null) |</span> <span class=\"highlight-line\">|       5 | 0 years 0 mons 2 days 0 hours 0 mins 0.00 secs |</span></code></pre> <p>Finally, let's filter out the extra rows, join this with the <code>users</code> table to get the activation method, and then group and average by that activation method:</p> <pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"highlight-line\"><span class=\"token keyword\">SELECT</span></span> <span class=\"highlight-line\">  activation_method<span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  <span class=\"token function\">avg</span><span class=\"token punctuation\">(</span>activation_delay<span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">FROM</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span></span> <span class=\"highlight-line\">  user_id<span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  created_at <span class=\"token operator\">-</span> LAG<span class=\"token punctuation\">(</span>created_at<span class=\"token punctuation\">,</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">OVER</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">PARTITION</span> <span class=\"token keyword\">BY</span> user_id <span class=\"token keyword\">ORDER</span> <span class=\"token keyword\">BY</span> created_at<span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> activation_delay</span> <span class=\"highlight-line\"><span class=\"token keyword\">FROM</span> user_events</span> <span class=\"highlight-line\"><span class=\"token keyword\">WHERE</span> user_id <span class=\"token operator\">in</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> id <span class=\"token keyword\">FROM</span> users <span class=\"token keyword\">WHERE</span> state <span class=\"token operator\">=</span> <span class=\"token string\">'active'</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\"><span class=\"token operator\">AND</span> state <span class=\"token operator\">IN</span> <span class=\"token punctuation\">(</span><span class=\"token string\">'pending'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'active'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> t</span> <span class=\"highlight-line\"><span class=\"token keyword\">JOIN</span> users <span class=\"token keyword\">ON</span> users<span class=\"token punctuation\">.</span>id <span class=\"token operator\">=</span> t<span class=\"token punctuation\">.</span>user_id</span> <span class=\"highlight-line\"><span class=\"token keyword\">WHERE</span> activation_delay <span class=\"token operator\">IS</span> <span class=\"token operator\">NOT</span> <span class=\"token boolean\">NULL</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">GROUP</span> <span class=\"token keyword\">BY</span> activation_method<span class=\"token punctuation\">;</span></span></code></pre> <p>And we're done!</p> <pre class=\"language-text\"><code class=\"language-text\"><span class=\"highlight-line\">| activation_method |                                            avg |</span> <span class=\"highlight-line\">|-------------------|------------------------------------------------|</span> <span class=\"highlight-line\">|             email | 0 years 0 mons 2 days 0 hours 0 mins 0.00 secs |</span> <span class=\"highlight-line\">|              text | 0 years 0 mons 0 days 3 hours 0 mins 0.00 secs |</span></code></pre> <p>We can see that users who activate via text message activate much sooner. Our Product Owner or Marketing Director would probably be interested in that.</p> <h2 id=\"adding-readability-with-with\" tabindex=\"-1\">Adding Readability with <code>WITH</code></h2> <p>So, how do <a href=\"https://www.postgresql.org/docs/current/queries-with.html\">Common Table Expressions</a> (AKA <code>WITH</code> queries) make this query better?</p> <p>Here's the idea: think of each <code>SELECT</code> in the above query as creating a temporary table, that only lives for the duration of the query. Instead of nesting those, we can pull them out, alias them, and move them all to the top. I like this for two reasons:</p> <ol> <li>This gives you the opportunity to assign names to each <code>SELECT</code> query, which acts like code-as-documentation.</li> <li>This allows you to organize your query as you would normally read: from top to bottom. With nested <code>SELECT</code>s, you have to read from inside out.</li> </ol> <p>So what does this look like?</p> <pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"highlight-line\"><span class=\"token keyword\">WITH</span></span> <span class=\"highlight-line\">  alias1 <span class=\"token keyword\">as</span> <span class=\"token punctuation\">(</span>select_query1<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  alias2 <span class=\"token keyword\">as</span> <span class=\"token punctuation\">(</span>select_query2<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">SELECT</span> <span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span></span></code></pre> <p>And of course, you can use previous &quot;temporary tables&quot; within subsequent ones.</p> <p>So, here's how to clean up the above query with <code>with</code>:</p> <pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"highlight-line\"><span class=\"token keyword\">WITH</span></span> <span class=\"highlight-line\">  active_user_ids <span class=\"token keyword\">as</span> <span class=\"token punctuation\">(</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">SELECT</span> id <span class=\"token keyword\">FROM</span> users <span class=\"token keyword\">WHERE</span> state <span class=\"token operator\">=</span> <span class=\"token string\">'active'</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  user_activation_delays <span class=\"token keyword\">as</span> <span class=\"token punctuation\">(</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">SELECT</span></span> <span class=\"highlight-line\">      user_id<span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">      created_at <span class=\"token operator\">-</span> LAG<span class=\"token punctuation\">(</span>created_at<span class=\"token punctuation\">,</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">OVER</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">PARTITION</span> <span class=\"token keyword\">BY</span> user_id <span class=\"token keyword\">ORDER</span> <span class=\"token keyword\">BY</span> created_at<span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> activation_delay</span> <span class=\"highlight-line\">    <span class=\"token keyword\">FROM</span> user_events</span> <span class=\"highlight-line\">    <span class=\"token keyword\">WHERE</span> user_id <span class=\"token operator\">in</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">from</span> active_user_ids<span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">    <span class=\"token operator\">AND</span> state <span class=\"token operator\">IN</span> <span class=\"token punctuation\">(</span><span class=\"token string\">'pending'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'active'</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">SELECT</span></span> <span class=\"highlight-line\">  activation_method<span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  <span class=\"token function\">avg</span><span class=\"token punctuation\">(</span>activation_delay<span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">FROM</span> user_activation_delays</span> <span class=\"highlight-line\"><span class=\"token keyword\">JOIN</span> users <span class=\"token keyword\">ON</span> users<span class=\"token punctuation\">.</span>id <span class=\"token operator\">=</span> user_activation_delays<span class=\"token punctuation\">.</span>user_id</span> <span class=\"highlight-line\"><span class=\"token keyword\">WHERE</span> activation_delay <span class=\"token operator\">IS</span> <span class=\"token operator\">NOT</span> <span class=\"token boolean\">NULL</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">GROUP</span> <span class=\"token keyword\">BY</span> activation_method<span class=\"token punctuation\">;</span></span></code></pre> <p>We've pulled out the two inner <code>SELECT</code>s and given them names, so it's very clear what their purpose is. Also, we can read this top-to-bottom and see the story behind how we've stitched this data together. Finally, notice that we can treat those &quot;temporary tables&quot; just like normal tables: joining, filtering, grouping.</p> ",
      "content_text": "When I'm writing ad hoc SQL queries, I often build them up slowly as I work through the problem at hand; usually, they take the form of several nested SELECT queries. However, that's rarely very readable, not great for sharing with the rest of the team, or for referring back to later. Recently, I've started using WITH queries to clean up my queries. An Example Let's look at a simple (and not too contrived, I hope) example. Let's say I'm investigating a state change in my users: I want to know how quickly they move from pending to active. If you want to follow along, check out the SQL Fiddle. Let's start by finding all active users. SELECT * FROM users WHERE state = 'active'; The result: | id |  state | activation_method |                  created_at | |----|--------|-------------------|-----------------------------| |  2 | active |             email | 2021-04-01T13:06:22.943296Z | |  3 | active |              text | 2021-04-06T11:06:22.943296Z | |  4 | active |              text | 2021-04-02T13:06:22.943296Z | |  5 | active |             email | 2021-04-03T13:06:22.943296Z | Then, let's find user_events for those users: SELECT * FROM user_events WHERE user_id in (SELECT id FROM users WHERE state = 'active') AND state IN ('pending', 'active'); Now we have a list of events where the state of currently-active users changed. | id | user_id |             action |   state |                  created_at | |----|---------|--------------------|---------|-----------------------------| |  2 |       2 | registered-account | pending | 2021-04-01T12:57:36.903034Z | |  3 |       2 |  activated-account |  active | 2021-04-03T12:57:36.903034Z | |  4 |       3 | registered-account | pending | 2021-04-06T10:57:36.903034Z | |  5 |       3 |  activated-account |  active | 2021-04-06T12:57:36.903034Z | |  6 |       4 | registered-account | pending | 2021-04-02T12:57:36.903034Z | |  8 |       4 |  activated-account |  active | 2021-04-02T16:57:36.903034Z | |  7 |       5 | registered-account | pending | 2021-04-04T12:57:36.903034Z | |  9 |       5 |  activated-account |  active | 2021-04-06T12:57:36.903034Z | Let's use a window function to find the activation delay. We'll take the difference between registration time and activation time: SELECT   user_id,   created_at - LAG(created_at, 1) OVER (PARTITION BY user_id ORDER BY created_at) as activation_delay FROM user_events WHERE user_id in (SELECT id FROM users WHERE state = 'active') AND state IN ('pending', 'active'); Nice! Now we can see how long each user took to activate. | user_id |                               activation_delay | |---------|------------------------------------------------| |       2 |                                         (null) | |       2 | 0 years 0 mons 2 days 0 hours 0 mins 0.00 secs | |       3 |                                         (null) | |       3 | 0 years 0 mons 0 days 2 hours 0 mins 0.00 secs | |       4 |                                         (null) | |       4 | 0 years 0 mons 0 days 4 hours 0 mins 0.00 secs | |       5 |                                         (null) | |       5 | 0 years 0 mons 2 days 0 hours 0 mins 0.00 secs | Finally, let's filter out the extra rows, join this with the users table to get the activation method, and then group and average by that activation method: SELECT   activation_method,   avg(activation_delay) FROM (SELECT   user_id,   created_at - LAG(created_at, 1) OVER (PARTITION BY user_id ORDER BY created_at) as activation_delay FROM user_events WHERE user_id in (SELECT id FROM users WHERE state = 'active') AND state IN ('pending', 'active')) AS t JOIN users ON users.id = t.user_id WHERE activation_delay IS NOT NULL GROUP BY activation_method; And we're done! | activation_method |                                            avg | |-------------------|------------------------------------------------| |             email | 0 years 0 mons 2 days 0 hours 0 mins 0.00 secs | |              text | 0 years 0 mons 0 days 3 hours 0 mins 0.00 secs | We can see that users who activate via text message activate much sooner. Our Product Owner or Marketing Director would probably be interested in that. Adding Readability with WITH So, how do Common Table Expressions (AKA WITH queries) make this query better? Here's the idea: think of each SELECT in the above query as creating a temporary table, that only lives for the duration of the query. Instead of nesting those, we can pull them out, alias them, and move them all to the top. I like this for two reasons:  This gives you the opportunity to assign names to each SELECT query, which acts like code-as-documentation. This allows you to organize your query as you would normally read: from top to bottom. With nested SELECTs, you have to read from inside out.  So what does this look like? WITH   alias1 as (select_query1),   alias2 as (select_query2),   ... SELECT ... And of course, you can use previous &quot;temporary tables&quot; within subsequent ones. So, here's how to clean up the above query with with: WITH   active_user_ids as (     SELECT id FROM users WHERE state = 'active'   ),   user_activation_delays as (     SELECT       user_id,       created_at - LAG(created_at, 1) OVER (PARTITION BY user_id ORDER BY created_at) as activation_delay     FROM user_events     WHERE user_id in (SELECT * from active_user_ids)     AND state IN ('pending', 'active')   ) SELECT   activation_method,   avg(activation_delay) FROM user_activation_delays JOIN users ON users.id = user_activation_delays.user_id WHERE activation_delay IS NOT NULL GROUP BY activation_method; We've pulled out the two inner SELECTs and given them names, so it's very clear what their purpose is. Also, we can read this top-to-bottom and see the story behind how we've stitched this data together. Finally, notice that we can treat those &quot;temporary tables&quot; just like normal tables: joining, filtering, grouping. ",
      "date_published": "2021-04-06T00:00:00.000Z",
      "tags": [
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/ts-string-theory/",
      "url": "https://shaky.sh/ts-string-theory/",
      "title": "TypeScript String Theory",
      "content_html": "<p>TypeScript brings power to even the humble string. Let's take a look at several ways we incorporate better string-based types into our code.</p> <h2 id=\"string-constant-types\" tabindex=\"-1\">String Constant Types</h2> <p>Let's start simple. You already know about the <code>string</code> type, but did you know you could assign a specific string value as a type?</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Notification</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    type<span class=\"token operator\">:</span> <span class=\"token string\">\"email\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    content<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>In our <code>Notification</code> type, the <code>content</code> can be any string value, but the <code>type</code> must always be <code>&quot;email&quot;</code>. What's the point? Why would you do this?</p> <p>For two reasons. The domain-related reason could be that you only support email notifications right now, but you want to add support for SMS later. You can ensure that, for now, your codebase can only have <code>Notification</code>s that are of type <code>email</code>. You might be tempted to leave the <code>type</code> field off entirely if there's only only possible value, but having a <code>type</code> field makes <code>Notification</code> <a href=\"https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle\">open to extension and closed for modification</a>. It'll be simple to add other notification types later.</p> <p>The other reason for literal string types is that you can use them to identify the type of an object via a discriminated union. Let's extend our example above to see how this works:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">EmailNotification</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    type<span class=\"token operator\">:</span> <span class=\"token string\">\"email\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    content<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    recipientEmailAddress<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">SmsNotification</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    type<span class=\"token operator\">:</span> <span class=\"token string\">\"sms\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    content<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    recipientPhoneNumber<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Notification</span> <span class=\"token operator\">=</span> EmailNotification <span class=\"token operator\">|</span> SmsNotification<span class=\"token punctuation\">;</span></span></code></pre> <p>We have two specific <code>Notification</code> types, and a union type made from all our more specific types.</p> <p>Now, let's say we need a <code>send</code> function:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">send</span><span class=\"token punctuation\">(</span>n<span class=\"token operator\">:</span> Notification<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token comment\">// ...</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>This function takes any <code>Notification</code>, but it needs to do something different depending on what type of notification it is. However, since <code>Notification</code> is the union of our email and sms types, we only have access to the <code>type</code> and <code>content</code> fields, since those are the only fields that are shared.</p> <p>This is where that string literal type comes in handy. It allows us to discriminate between the types in the union:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">send</span><span class=\"token punctuation\">(</span>n<span class=\"token operator\">:</span> Notification<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">switch</span><span class=\"token punctuation\">(</span>n<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">        <span class=\"token keyword\">case</span> <span class=\"token string\">\"email\"</span><span class=\"token operator\">:</span></span> <span class=\"highlight-line\">            <span class=\"token keyword\">return</span> <span class=\"token function\">sendEmail</span><span class=\"token punctuation\">(</span>n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">        <span class=\"token keyword\">case</span> <span class=\"token string\">\"sms\"</span><span class=\"token operator\">:</span></span> <span class=\"highlight-line\">            <span class=\"token keyword\">return</span> <span class=\"token function\">sendSms</span><span class=\"token punctuation\">(</span>n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">        <span class=\"token keyword\">default</span><span class=\"token operator\">:</span></span> <span class=\"highlight-line\">            <span class=\"token function\">unreachable</span><span class=\"token punctuation\">(</span>n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">sendEmail</span><span class=\"token punctuation\">(</span>emailNotif<span class=\"token operator\">:</span> EmailNotification<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">sendSms</span><span class=\"token punctuation\">(</span>smsNotif<span class=\"token operator\">:</span> SmsNotification<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">unreachable</span><span class=\"token punctuation\">(</span>x<span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token builtin\">never</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"unreachable!\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>There are a number of cool things going on here.</p> <p>First, the differentiation. As we already established, the argument <code>n</code> is of type <code>Notification</code>, so we can't access the <code>recipientEmailAddress</code> or <code>recipientPhoneNumber</code> fields. However, because the <code>type</code> field is a literal string (and not just the type <code>string</code>) for both, TypeScript can use that to <em>narrow</em> the type of <code>n</code>. That is, we can discriminate between the types in our union (<code>Notification</code>) by comparing <code>n.type</code>. This means that inside the case statements, <code>n</code> is now known to be an <code>EmailNotification</code> or <code>SmsNotification</code>, and we can treat it as such.</p> <p>Secondly, we're using a pattern called exhaustive switch here — that is, we're using TypeScript to guarantee that our switch statement covers all possible values for <code>n.type</code>. Because of the discrimination behavior, TypeScript knows that if we read the <code>default</code> case, there's no other possible type for <code>n</code>, and so it will be <code>never</code>. We have a little utility function that takes a <code>never</code> and throws an error. This performs double duty. Most obviously, it will throw an error if we ever hit the <code>default</code> case. But even better, we have a &quot;compile time&quot; error: if we add a new type to our union — say, <code>PigeonNotification</code> with <code>type: &quot;pigeon&quot;</code> — and we forget to add a <code>case</code> statement for that, then we'll get an error on our call to <code>unreachable</code>:</p> <pre class=\"language-text\"><code class=\"language-text\"><span class=\"highlight-line\">Argument of type 'PigeonNotification' is not assignable to parameter of type 'never'.</span></code></pre> <p>Of course, with language servers running in the editor, this compile time error becomes  a &quot;coding time&quot; error, and we get an inline reminder to update the <code>send</code> function.</p> <h2 id=\"string-unions\" tabindex=\"-1\">String Unions</h2> <p>We can use literal strings to create their own unions as well. For example:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">NotificationType</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"email\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"sms\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"pigeon\"</span><span class=\"token punctuation\">;</span></span></code></pre> <p>This is actually the same as using the square bracket notation on a type to get the type of a field within it:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">NotificationType</span> <span class=\"token operator\">=</span> Notification<span class=\"token punctuation\">[</span><span class=\"token string\">\"type\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></span></code></pre> <p>A string union is a great way to represent a discrete set of values. Types of notifications? Absolutely! How about the possible states of a job that sends notifications? You bet:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">JobState</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"enqueued\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"running\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"failed\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"complete\"</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Or, what about the list of the names of the databases your app connects to? Yep:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">DatabaseName</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"users\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"widgets\"</span>  <span class=\"token operator\">|</span> <span class=\"token string\">\"events\"</span><span class=\"token punctuation\">;</span></span></code></pre> <p>You can do a couple cool things with these string unions.</p> <p>First, you can create permutations of multiple unions:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">NotificationType</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"email\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"sms\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"pigeon\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">JobState</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"enqueued\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"running\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"failed\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"complete\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">NotifcationJobState</span> <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>NotificationType<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>Capitalize<span class=\"token operator\">&lt;</span>JobState<span class=\"token operator\">></span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span></span></code></pre> <p>Notice that we can use the template literal syntax to create a type. We can use this exactly like we do in regular JavaScript, where we include both literal characters and variables for replacement.</p> <p>We're also using one of TypeScript's string manipulation types, <code>Capitalize</code>, which capitalizes the first letter of the string. TypeScript offers four such string manipulation types:</p> <ul> <li><code>Uncapitalize</code></li> <li><code>Capitalize</code></li> <li><code>Uppercase</code></li> <li><code>Lowercase</code></li> </ul> <p>But what exactly is the result of all this? What's the resulting type <code>NotificationJobState</code>? Well, it's another string union, one with all permutations of the two string unions &quot;inside&quot; it. It's the equivalent of this:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">NotificationJobState</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"emailEnqueued\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"emailRunning\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"emailFailed\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"emailComplete\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"smsEnqueued\"</span> <span class=\"token operator\">|</span> <span class=\"token operator\">...</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"pigeonComplete\"</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Of course, the benefit of creating one type based on another is that all your types will be kept &quot;in sync&quot; — if you add a new notification type or job state, the new values will be part of the permutations.</p> <h2 id=\"mapping-string-types\" tabindex=\"-1\">Mapping String Types</h2> <p>We can use string unions to create more complex types using type mapping. Let's create a <code>DatabaseConfigs</code> type based on that <code>DatabaseName</code> string union we have above</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">DatabaseName</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"users\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"widgets\"</span>  <span class=\"token operator\">|</span> <span class=\"token string\">\"events\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">DatabaseConfigs</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">[</span>key <span class=\"token keyword\">in</span> DatabaseName<span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">        host<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">        port<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">        user<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">        pass<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span></code></pre> <p>The <code>key in OtherType</code> syntax is the mapping. This means that an instance of <code>DatabaseConfig</code>s needs to have three properties matching strings in <code>DatabaseName</code>.</p> <p>Mapped types do save you some keystrokes, but they also improve your development experience. Let’s say we have our <code>DatabaseConfigs</code> instance:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">const</span> dbConfig<span class=\"token operator\">:</span> DatabaseConfigs <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    users<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">    widgets<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">    events<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span> <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>If we add a new database to our app (say, <code>orders</code>) and we add its name to the <code>DatabaseName</code> string union, it will automatically become part of the <code>DatabaseConfig</code> type. We’ll immediately get a TypeScript error at our <code>dbConfig</code> object, saying that it’s missing an <code>orders</code> field, and reminding us to add the connection details.</p> <h2 id=\"unions-with-keyof\" tabindex=\"-1\">Unions with <code>keyof</code></h2> <p>There's another way you can create string unions: using the <code>keyof</code> keyword. In conjunction with another type, <code>keyof</code> will create a union from all the keys on that type.</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">User</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    firstName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    lastName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    age<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    verified<span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">UserField</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">keyof</span> User<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token comment\">// equivalent to \"firstName\" | \"lastName\" | \"age\" | \"verified\"</span></span></code></pre> <p>We can use this with type mapping and the template literal syntax to do some cool and complex stuff:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">User</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    firstName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    lastName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    age<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    verified<span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">UserGetter</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">[</span>Key <span class=\"token keyword\">in</span> <span class=\"token keyword\">keyof</span> User <span class=\"token keyword\">as</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">get</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>Capitalize<span class=\"token operator\">&lt;</span>Key<span class=\"token operator\">></span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> User<span class=\"token punctuation\">[</span>Key<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">UserSetter</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">[</span>Key <span class=\"token keyword\">in</span> <span class=\"token keyword\">keyof</span> User <span class=\"token keyword\">as</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">set</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>Capitalize<span class=\"token operator\">&lt;</span>Key<span class=\"token operator\">></span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>arg<span class=\"token operator\">:</span> User<span class=\"token punctuation\">[</span>Key<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>We're putting <code>keyof User</code> inline here, but we could just as easily create an explicit type for it. We're also using the <code>in-as</code> syntax for mapping here, which allows us to transform the key using a template literal. In our case, we're ensuring that our <code>UserGetter</code> and <code>UserSetter</code> types will use conventional casing for their method names. These two types will make it easy for us to ensure that any time we add new fields to our <code>User</code> type, we'll be reminded to add the correct methods (with the correct types!) to anything implementing <code>UserGetter</code> and <code>UserSetter</code>.</p> <h2 id=\"read-only-strings\" tabindex=\"-1\">Read-Only Strings</h2> <p>Let's wrap up with an interesting example of crossing the compile time and runtime boundary. We know that when TypeScript is transpiled to JavaScript, the types are stripped out. Because of this, we sometimes &quot;know better&quot; than the compiler. Check out this example:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">User</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    firstName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    lastName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    age<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    verified<span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">const</span> u<span class=\"token operator\">:</span> User <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  firstName<span class=\"token operator\">:</span> <span class=\"token string\">\"Jane\"</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  lastName<span class=\"token operator\">:</span> <span class=\"token string\">\"Doe\"</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  age<span class=\"token operator\">:</span> <span class=\"token number\">50</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  verified<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">const</span> keys <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"firstName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"lastName\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">keys<span class=\"token punctuation\">.</span><span class=\"token function\">forEach</span><span class=\"token punctuation\">(</span>key <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  u<span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> u<span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span><span class=\"token function\">toLowerCase</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>We have an instance of our <code>User</code> type, and we want to iterate over an explicit subset of the keys, so we put them in an array. We can read this code and know that it works fine.</p> <p>However, TypeScript complains:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\">Element implicitly has an <span class=\"token string\">'any'</span> <span class=\"token keyword\">type</span> <span class=\"token class-name\">because</span> expression <span class=\"token keyword\">of</span> <span class=\"token keyword\">type</span> <span class=\"token string\">'string'</span> can<span class=\"token string\">'t be used to index type '</span>User'<span class=\"token punctuation\">.</span></span></code></pre> <p>The problem is that TypeScript considers <code>keys</code> to have the type <code>Array&lt;string&gt;</code>, which is too &quot;wide&quot; to be used to index into our user (<code>u[key]</code>). The array could include strings that aren't keys of <code>User</code>!</p> <p>You might think that this is the solution, because it limits the array to including only strings that are keys of <code>User</code>:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">const</span> keys<span class=\"token operator\">:</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span><span class=\"token keyword\">keyof</span> User<span class=\"token operator\">></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"firstName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"lastName\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></span></code></pre> <p>This will solve that problem, but another one pops up:</p> <pre class=\"language-text\"><code class=\"language-text\"><span class=\"highlight-line\">Property 'toLowerCase' does not exist on type 'string | number | boolean'.</span></code></pre> <p>Now we can index into the object with <code>u[key]</code>, but we can't know for sure that we're operating on a string, since <code>User</code> includes non-string values.</p> <p>The cleanest way to do this is using <code>as const</code>:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">const</span> keys <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"firstName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"lastName\"</span><span class=\"token punctuation\">]</span> <span class=\"token keyword\">as</span> <span class=\"token keyword\">const</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token comment\">// equivalent to</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">const</span> keys<span class=\"token operator\">:</span> <span class=\"token keyword\">readonly</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"firstName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"lastName\"</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"firstName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"lastName\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></span></code></pre> <p>You’ve likely used <code>const</code> to create a variable with an unchangeable value, but this is different. When you append <code>as const</code> to a value, you’re telling TypeScript that the type of this object exactly matches the object itself; that is, all the fields in the object (or items in the array) are literal values, just like in the example we started with, where <code>Notification</code>’s <code>type</code> field is a string literal type.</p> <p>In this case, it will give <code>keys</code> the type of a read-only tuple with exactly those two strings inside it.</p> <p>Because they're string literals, TypeScript can validate that <code>u[key]</code> is always a string. And because <code>keys</code> is constant, or read-only, trying to do something like <code>keys.push(&quot;age&quot;)</code> or <code>keys[2] = &quot;verified&quot;</code> would result in TypeScript throwing an error.</p> <p>One final note: you don’t need to use <code>as const</code> with primitive values: if no type information is given, TypeScript will infer that they are literal types.</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">NotificationType</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"email\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"sms\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"pigeon\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">JobState</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"enqueued\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"running\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"failed\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"complete\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">NotifcationJobState</span> <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>NotificationType<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">_</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>JobState<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">update</span><span class=\"token punctuation\">(</span>s<span class=\"token operator\">:</span> NotifcationJobState<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">const</span> t <span class=\"token operator\">=</span> <span class=\"token string\">\"email\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">const</span> s <span class=\"token operator\">=</span> <span class=\"token string\">\"running\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token function\">update</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>t<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">_</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>s<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span></span></code></pre> <p>This works because the type of <code>t</code> is <code>”email”</code>, not <code>string</code>; same with <code>s</code>. If either had the type <code>string</code>, this would cause a type error.</p> <h2 id=\"conclusion\" tabindex=\"-1\">Conclusion</h2> <p>TypeScript takes the humble string and makes it a powerful tool for well-typed applications. We use all of these techniques to reduce errors and keep our whole codebase flexible as it grows.</p> ",
      "content_text": "TypeScript brings power to even the humble string. Let's take a look at several ways we incorporate better string-based types into our code. String Constant Types Let's start simple. You already know about the string type, but did you know you could assign a specific string value as a type? type Notification = {     type: \"email\";     content: string; } In our Notification type, the content can be any string value, but the type must always be &quot;email&quot;. What's the point? Why would you do this? For two reasons. The domain-related reason could be that you only support email notifications right now, but you want to add support for SMS later. You can ensure that, for now, your codebase can only have Notifications that are of type email. You might be tempted to leave the type field off entirely if there's only only possible value, but having a type field makes Notification open to extension and closed for modification. It'll be simple to add other notification types later. The other reason for literal string types is that you can use them to identify the type of an object via a discriminated union. Let's extend our example above to see how this works: type EmailNotification = {     type: \"email\";     content: string;     recipientEmailAddress: string; }  type SmsNotification = {     type: \"sms\";     content: string;     recipientPhoneNumber: string; }  type Notification = EmailNotification | SmsNotification; We have two specific Notification types, and a union type made from all our more specific types. Now, let's say we need a send function: function send(n: Notification) {     // ... } This function takes any Notification, but it needs to do something different depending on what type of notification it is. However, since Notification is the union of our email and sms types, we only have access to the type and content fields, since those are the only fields that are shared. This is where that string literal type comes in handy. It allows us to discriminate between the types in the union: function send(n: Notification) {     switch(n.type) {         case \"email\":             return sendEmail(n);         case \"sms\":             return sendSms(n);         default:             unreachable(n);     } }  function sendEmail(emailNotif: EmailNotification) {}  function sendSms(smsNotif: SmsNotification) {}  function unreachable(x: never): never {     throw new Error(\"unreachable!\"); } There are a number of cool things going on here. First, the differentiation. As we already established, the argument n is of type Notification, so we can't access the recipientEmailAddress or recipientPhoneNumber fields. However, because the type field is a literal string (and not just the type string) for both, TypeScript can use that to narrow the type of n. That is, we can discriminate between the types in our union (Notification) by comparing n.type. This means that inside the case statements, n is now known to be an EmailNotification or SmsNotification, and we can treat it as such. Secondly, we're using a pattern called exhaustive switch here — that is, we're using TypeScript to guarantee that our switch statement covers all possible values for n.type. Because of the discrimination behavior, TypeScript knows that if we read the default case, there's no other possible type for n, and so it will be never. We have a little utility function that takes a never and throws an error. This performs double duty. Most obviously, it will throw an error if we ever hit the default case. But even better, we have a &quot;compile time&quot; error: if we add a new type to our union — say, PigeonNotification with type: &quot;pigeon&quot; — and we forget to add a case statement for that, then we'll get an error on our call to unreachable: Argument of type 'PigeonNotification' is not assignable to parameter of type 'never'. Of course, with language servers running in the editor, this compile time error becomes  a &quot;coding time&quot; error, and we get an inline reminder to update the send function. String Unions We can use literal strings to create their own unions as well. For example: type NotificationType = \"email\" | \"sms\" | \"pigeon\"; This is actually the same as using the square bracket notation on a type to get the type of a field within it: type NotificationType = Notification[\"type\"]; A string union is a great way to represent a discrete set of values. Types of notifications? Absolutely! How about the possible states of a job that sends notifications? You bet: type JobState = \"enqueued\" | \"running\" | \"failed\" | \"complete\"; Or, what about the list of the names of the databases your app connects to? Yep: type DatabaseName = \"users\" | \"widgets\"  | \"events\"; You can do a couple cool things with these string unions. First, you can create permutations of multiple unions: type NotificationType = \"email\" | \"sms\" | \"pigeon\"; type JobState = \"enqueued\" | \"running\" | \"failed\" | \"complete\";  type NotifcationJobState = `${NotificationType}${Capitalize&lt;JobState>}`; Notice that we can use the template literal syntax to create a type. We can use this exactly like we do in regular JavaScript, where we include both literal characters and variables for replacement. We're also using one of TypeScript's string manipulation types, Capitalize, which capitalizes the first letter of the string. TypeScript offers four such string manipulation types:  Uncapitalize Capitalize Uppercase Lowercase  But what exactly is the result of all this? What's the resulting type NotificationJobState? Well, it's another string union, one with all permutations of the two string unions &quot;inside&quot; it. It's the equivalent of this: type NotificationJobState = \"emailEnqueued\" | \"emailRunning\" | \"emailFailed\" | \"emailComplete\" | \"smsEnqueued\" | ... | \"pigeonComplete\"; Of course, the benefit of creating one type based on another is that all your types will be kept &quot;in sync&quot; — if you add a new notification type or job state, the new values will be part of the permutations. Mapping String Types We can use string unions to create more complex types using type mapping. Let's create a DatabaseConfigs type based on that DatabaseName string union we have above type DatabaseName = \"users\" | \"widgets\"  | \"events\";  type DatabaseConfigs = {     [key in DatabaseName]: {         host: string;         port: number;         user: string;         pass: string     } }; The key in OtherType syntax is the mapping. This means that an instance of DatabaseConfigs needs to have three properties matching strings in DatabaseName. Mapped types do save you some keystrokes, but they also improve your development experience. Let’s say we have our DatabaseConfigs instance: const dbConfig: DatabaseConfigs = {     users: { ... },     widgets: { ... },     events: { ... } } If we add a new database to our app (say, orders) and we add its name to the DatabaseName string union, it will automatically become part of the DatabaseConfig type. We’ll immediately get a TypeScript error at our dbConfig object, saying that it’s missing an orders field, and reminding us to add the connection details. Unions with keyof There's another way you can create string unions: using the keyof keyword. In conjunction with another type, keyof will create a union from all the keys on that type. type User = {     firstName: string;     lastName: string;     age: number;     verified: boolean; }  type UserField = keyof User;  // equivalent to \"firstName\" | \"lastName\" | \"age\" | \"verified\" We can use this with type mapping and the template literal syntax to do some cool and complex stuff: type User = {     firstName: string;     lastName: string;     age: number;     verified: boolean; }  type UserGetter = {     [Key in keyof User as `get${Capitalize&lt;Key>}`]: () => User[Key]; }  type UserSetter = {     [Key in keyof User as `set${Capitalize&lt;Key>}`]: (arg: User[Key]) => void; } We're putting keyof User inline here, but we could just as easily create an explicit type for it. We're also using the in-as syntax for mapping here, which allows us to transform the key using a template literal. In our case, we're ensuring that our UserGetter and UserSetter types will use conventional casing for their method names. These two types will make it easy for us to ensure that any time we add new fields to our User type, we'll be reminded to add the correct methods (with the correct types!) to anything implementing UserGetter and UserSetter. Read-Only Strings Let's wrap up with an interesting example of crossing the compile time and runtime boundary. We know that when TypeScript is transpiled to JavaScript, the types are stripped out. Because of this, we sometimes &quot;know better&quot; than the compiler. Check out this example: type User = {     firstName: string;     lastName: string;     age: number;     verified: boolean; }  const u: User = {   firstName: \"Jane\",   lastName: \"Doe\",   age: 50,   verified: true };  const keys = [\"firstName\", \"lastName\"];  keys.forEach(key => {   u[key] = u[key].toLowerCase(); }); We have an instance of our User type, and we want to iterate over an explicit subset of the keys, so we put them in an array. We can read this code and know that it works fine. However, TypeScript complains: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'User'. The problem is that TypeScript considers keys to have the type Array&lt;string&gt;, which is too &quot;wide&quot; to be used to index into our user (u[key]). The array could include strings that aren't keys of User! You might think that this is the solution, because it limits the array to including only strings that are keys of User: const keys: Array&lt;keyof User> = [\"firstName\", \"lastName\"]; This will solve that problem, but another one pops up: Property 'toLowerCase' does not exist on type 'string | number | boolean'. Now we can index into the object with u[key], but we can't know for sure that we're operating on a string, since User includes non-string values. The cleanest way to do this is using as const: const keys = [\"firstName\", \"lastName\"] as const;  // equivalent to const keys: readonly [\"firstName\", \"lastName\"] = [\"firstName\", \"lastName\"]; You’ve likely used const to create a variable with an unchangeable value, but this is different. When you append as const to a value, you’re telling TypeScript that the type of this object exactly matches the object itself; that is, all the fields in the object (or items in the array) are literal values, just like in the example we started with, where Notification’s type field is a string literal type. In this case, it will give keys the type of a read-only tuple with exactly those two strings inside it. Because they're string literals, TypeScript can validate that u[key] is always a string. And because keys is constant, or read-only, trying to do something like keys.push(&quot;age&quot;) or keys[2] = &quot;verified&quot; would result in TypeScript throwing an error. One final note: you don’t need to use as const with primitive values: if no type information is given, TypeScript will infer that they are literal types. type NotificationType = \"email\" | \"sms\" | \"pigeon\"; type JobState = \"enqueued\" | \"running\" | \"failed\" | \"complete\";  type NotifcationJobState = `${NotificationType}_${JobState}`;  function update(s: NotifcationJobState) {}  const t = \"email\"; const s = \"running\"; update(`${t}_${s}`) This works because the type of t is ”email”, not string; same with s. If either had the type string, this would cause a type error. Conclusion TypeScript takes the humble string and makes it a powerful tool for well-typed applications. We use all of these techniques to reduce errors and keep our whole codebase flexible as it grows. ",
      "date_published": "2022-05-04T00:00:00.000Z",
      "tags": [
        "typescript",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/how-to-update-a-map-in-rust/",
      "url": "https://shaky.sh/how-to-update-a-map-in-rust/",
      "title": "How to update a map in rust",
      "content_html": "<p>I'm learning <a href=\"https://www.rust-lang.org/\">rust</a>, and it's been pretty tough to get used to the borrowing model.</p> <p>Here's a scenario that baffled me:</p> <pre class=\"language-rust\"><code class=\"language-rust\"><span class=\"highlight-line\"><span class=\"token keyword\">use</span> <span class=\"token namespace\">std<span class=\"token punctuation\">::</span>collections<span class=\"token punctuation\">::</span></span><span class=\"token class-name\">HashMap</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">fn</span> <span class=\"token function-definition function\">main</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">let</span> <span class=\"token keyword\">mut</span> my_map <span class=\"token operator\">=</span> <span class=\"token class-name\">HashMap</span><span class=\"token punctuation\">::</span><span class=\"token function\">from</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"one\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">    <span class=\"token keyword\">let</span> val <span class=\"token operator\">=</span> my_map<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"one\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">unwrap</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    my_map<span class=\"token punctuation\">.</span><span class=\"token function\">insert</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"one\"</span><span class=\"token punctuation\">,</span> val <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>This feels like a straightforward operation: updating a value in a map. But the compiler complains about this:</p> <pre class=\"language-rust\"><code class=\"language-rust\"><span class=\"highlight-line\"><span class=\"token keyword\">use</span> <span class=\"token namespace\">std<span class=\"token punctuation\">::</span>collections<span class=\"token punctuation\">::</span></span><span class=\"token class-name\">HashMap</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">fn</span> <span class=\"token function-definition function\">main</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">let</span> <span class=\"token keyword\">mut</span> my_map <span class=\"token operator\">=</span> <span class=\"token class-name\">HashMap</span><span class=\"token punctuation\">::</span><span class=\"token function\">from</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"one\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">    <span class=\"token keyword\">let</span> val <span class=\"token operator\">=</span> my_map<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"one\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">unwrap</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">           <span class=\"token comment\">// ----------------- immutable borrow occurs here</span></span> <span class=\"highlight-line\">    my_map<span class=\"token punctuation\">.</span><span class=\"token function\">insert</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"one\"</span><span class=\"token punctuation\">,</span> val <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"> <span class=\"token comment\">// ^^^^^^^^^^^^^^^^^^^^^---^^^^^</span></span> <span class=\"highlight-line\"> <span class=\"token comment\">// |                    |</span></span> <span class=\"highlight-line\"> <span class=\"token comment\">// |                    immutable borrow later used here</span></span> <span class=\"highlight-line\"> <span class=\"token comment\">// mutable borrow occurs here</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>Updating a value in a map is something I do all the time in JavaScript, why is it so hard in rust?</p> <p>The problem is that I'm using <code>val</code>, which is a reference to a value in <code>my_map</code>, in <strong>the same statement</strong> that updates <code>my_map</code>. As I understand it, <code>my_map</code> might need to move or allocate more memory as part of the insert operation, and in the process of that, the <code>val</code> reference might become (essentially) a null pointer, which rust prevents.</p> <p>The solution is simple:</p> <pre class=\"language-rust\"><code class=\"language-rust\"><span class=\"highlight-line\"><span class=\"token keyword\">let</span> val <span class=\"token operator\">=</span> my_map<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"one\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">unwrap</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">let</span> new_val <span class=\"token operator\">=</span> val <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">my_map<span class=\"token punctuation\">.</span><span class=\"token function\">insert</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"one\"</span><span class=\"token punctuation\">,</span> new_val<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Just allocate a new variable with the new value first! Then, when I'm doing the insert operation, I'm not using a reference to <code>my_map</code> memory at all.</p> <p>There's another way to do this that's mind-bending for me:</p> <pre class=\"language-rust\"><code class=\"language-rust\"><span class=\"highlight-line\"><span class=\"token keyword\">let</span> val <span class=\"token operator\">=</span> my_map<span class=\"token punctuation\">.</span><span class=\"token function\">get_mut</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"one\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">unwrap</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token operator\">*</span>val <span class=\"token operator\">=</span> <span class=\"token operator\">*</span>val <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span></span></code></pre> <p>We get a mutable reference to our map value, and then we can assign directly to that reference! I imagine this makes a ton of sense if you're coming from C, or another language with pointers or references. But for this JavaScript guy, that feels very weird.</p> ",
      "content_text": "I'm learning rust, and it's been pretty tough to get used to the borrowing model. Here's a scenario that baffled me: use std::collections::HashMap;  fn main() {     let mut my_map = HashMap::from([(\"one\", 1)]);      let val = my_map.get(\"one\").unwrap();     my_map.insert(\"one\", val + 1); } This feels like a straightforward operation: updating a value in a map. But the compiler complains about this: use std::collections::HashMap;  fn main() {     let mut my_map = HashMap::from([(\"one\", 1)]);      let val = my_map.get(\"one\").unwrap();            // ----------------- immutable borrow occurs here     my_map.insert(\"one\", val + 1);  // ^^^^^^^^^^^^^^^^^^^^^---^^^^^  // |                    |  // |                    immutable borrow later used here  // mutable borrow occurs here } Updating a value in a map is something I do all the time in JavaScript, why is it so hard in rust? The problem is that I'm using val, which is a reference to a value in my_map, in the same statement that updates my_map. As I understand it, my_map might need to move or allocate more memory as part of the insert operation, and in the process of that, the val reference might become (essentially) a null pointer, which rust prevents. The solution is simple: let val = my_map.get(\"one\").unwrap(); let new_val = val + 1; my_map.insert(\"one\", new_val); Just allocate a new variable with the new value first! Then, when I'm doing the insert operation, I'm not using a reference to my_map memory at all. There's another way to do this that's mind-bending for me: let val = my_map.get_mut(\"one\").unwrap(); *val = *val + 1; We get a mutable reference to our map value, and then we can assign directly to that reference! I imagine this makes a ton of sense if you're coming from C, or another language with pointers or references. But for this JavaScript guy, that feels very weird. ",
      "date_published": "2022-07-20T00:00:00.000Z",
      "tags": [
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/why-tmux/",
      "url": "https://shaky.sh/why-tmux/",
      "title": "The benefits of using tmux",
      "content_html": "<p>I've used <a href=\"https://github.com/tmux/tmux\">tmux</a> to manage multiple open terminals for years now. There are two reasons that really make the experience for me. Both are related to how you can detach from a running tmux session and then reconnect to it.</p> <h2 id=\"restore-a-dropped-session\" tabindex=\"-1\">Restore a dropped session</h2> <p>When you're moving between your terminal and other applications all day, you're likely to accidentally close a window at some point. In a standard shell, that means you've just lost whatever state you had: running processes, ad-hoc aliases, vim buffers, etc. If you accidentally close a terminal window that's running tmux, no sweat. You can just open a new window, attach to the existing tmux session, and keep going!</p> <pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"highlight-line\">tmux attach <span class=\"token parameter variable\">-t</span> <span class=\"token operator\">&lt;</span>session-name-or-index<span class=\"token operator\">></span></span></code></pre> <h2 id=\"pop-in-across-machines\" tabindex=\"-1\">Pop in across machines</h2> <p>Since I work remotely, I have a work and personal machine on my home network. I keep them as separate as possible, but sometimes a work idea will strike me when I'm on my personal machine, or vice versa. I can easily SSH from one machine to the other, and then attach to a running tmux session. That session will have the state of my current project all ready to go. I can easily jot down a few notes or lines of code, and then disconnect. No need to worry about, say, a file already being open in another process: I can use the same vim process that's likely still open on my other machine.</p> <p>Of course, tmux has so much more to offer, but I haven't seen these capabilities elsewhere.</p> ",
      "content_text": "I've used tmux to manage multiple open terminals for years now. There are two reasons that really make the experience for me. Both are related to how you can detach from a running tmux session and then reconnect to it. Restore a dropped session When you're moving between your terminal and other applications all day, you're likely to accidentally close a window at some point. In a standard shell, that means you've just lost whatever state you had: running processes, ad-hoc aliases, vim buffers, etc. If you accidentally close a terminal window that's running tmux, no sweat. You can just open a new window, attach to the existing tmux session, and keep going! tmux attach -t &lt;session-name-or-index> Pop in across machines Since I work remotely, I have a work and personal machine on my home network. I keep them as separate as possible, but sometimes a work idea will strike me when I'm on my personal machine, or vice versa. I can easily SSH from one machine to the other, and then attach to a running tmux session. That session will have the state of my current project all ready to go. I can easily jot down a few notes or lines of code, and then disconnect. No need to worry about, say, a file already being open in another process: I can use the same vim process that's likely still open on my other machine. Of course, tmux has so much more to offer, but I haven't seen these capabilities elsewhere. ",
      "date_published": "2022-07-26T00:00:00.000Z",
      "tags": [
        "tech",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/ts-bit-flags/",
      "url": "https://shaky.sh/ts-bit-flags/",
      "title": "Bit flags in TypeScript",
      "content_html": "<p>I recently made <a href=\"https://www.youtube.com/watch?v=pWPClHdcvVg\">a video about TypeScript Enums</a>, and why you might not want to use them. But I want to go a little deeper on some seemingly strange enum behaviour.</p> <p>You might not expect this to be valid TypeScript:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">enum</span> Role <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  Executive <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  Manager <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  Engineer <span class=\"token operator\">=</span> <span class=\"token number\">2</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">const</span> myRole<span class=\"token operator\">:</span> Role <span class=\"token operator\">=</span> <span class=\"token number\">3</span><span class=\"token punctuation\">;</span></span></code></pre> <p>But it is. We can assign a value that isn't part of <code>Role</code> to a variable of type <code>Role</code>. Why would TypeScript allow this?</p> <p>The reason seems to be supporting bit flags in TypeScript. The idea behind bit flags is that you can represent many boolean values in a single number, because that number can be represented in binary:</p> <pre class=\"language-text\"><code class=\"language-text\"><span class=\"highlight-line\">0 = 000</span> <span class=\"highlight-line\">1 = 001</span> <span class=\"highlight-line\">2 = 010</span> <span class=\"highlight-line\">3 = 011</span> <span class=\"highlight-line\">4 = 100</span> <span class=\"highlight-line\">5 = 101</span> <span class=\"highlight-line\">6 = 110</span> <span class=\"highlight-line\">7 = 111</span></code></pre> <p>The first eight numbers (0 – 7) can all be represented as 3-digit binary numbers. In binary form, you can see how they can also represent all possible combinations of three boolean fields. The &quot;ones column&quot; represents the first boolean field, and so on.</p> <p>If we want a TypeScript enum that represents a set of three boolean fields, we only need three members in the enum:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">enum</span> UserAttrs <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  Verified <span class=\"token operator\">=</span> <span class=\"token number\">1</span> <span class=\"token operator\">&lt;&lt;</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 1</span></span> <span class=\"highlight-line\">  Active   <span class=\"token operator\">=</span> <span class=\"token number\">1</span> <span class=\"token operator\">&lt;&lt;</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 2</span></span> <span class=\"highlight-line\">  Paying   <span class=\"token operator\">=</span> <span class=\"token number\">1</span> <span class=\"token operator\">&lt;&lt;</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 4</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>By convention, we're using the left-shift operator on <code>1</code> to set the values for these enum members. But we could have just as easily assigned the matching decimal numbers instead. When you left-shift <code>1</code>, you're essentially choosing the column you want the binary <code>1</code> to be in. You can see how <code>1</code>, <code>2</code>, and <code>4</code> in the table above each have a single <code>1</code> in their respective columns.</p> <p>Now, we can use this enum to create different combinations of attributes:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">const</span> verifiedAndActive <span class=\"token operator\">=</span> UserAttrs<span class=\"token punctuation\">.</span>Verified <span class=\"token operator\">|</span> UserAttrs<span class=\"token punctuation\">.</span>Active<span class=\"token punctuation\">;</span> <span class=\"token comment\">// 3 = 011</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">const</span> activeAndPaying <span class=\"token operator\">=</span> UserAttrs<span class=\"token punctuation\">.</span>Active <span class=\"token operator\">|</span> UserAttrs<span class=\"token punctuation\">.</span>Paying<span class=\"token punctuation\">;</span>     <span class=\"token comment\">// 6 = 110</span></span></code></pre> <p>We're combining these attributes with the <code>OR</code> operator, and this works much like a union in a TypeScript type: you get a value that can be either side of the <code>OR</code> operator (or both sides, in our case!). And these new values can be treated as being the type <code>UserAttrs</code>. As I understand it, this is the main reason you can assign any number to an enum type in TypeScript: it could be a combination of actual members of the enum. Notice that in our new values, a <code>1</code> in the &quot;ones column&quot; represents a user who has <code>verified=true</code>, a <code>1</code> in the &quot;tens column&quot; represents a user who has <code>active=true</code>, etc.</p> <p>Now, you might wonder how we get the individual values out of our new combined values. Easy: use the <code>AND</code> operator:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">isVerified</span><span class=\"token punctuation\">(</span>attrs<span class=\"token operator\">:</span> UserAttrs<span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">\t<span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>attrs <span class=\"token operator\">&amp;</span> UserAttrs<span class=\"token punctuation\">.</span>Verified<span class=\"token punctuation\">)</span> <span class=\"token operator\">===</span> UserAttrs<span class=\"token punctuation\">.</span>Verified<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token function\">isVerified</span><span class=\"token punctuation\">(</span>activeAndPaying<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>   <span class=\"token comment\">// false</span></span> <span class=\"highlight-line\"><span class=\"token function\">isVerified</span><span class=\"token punctuation\">(</span>verifiedAndActive<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// true</span></span></code></pre> <p>Again like in a TS type, the AND operator will give you anything that both sides share in common. Since <code>UserAttrs.Verified</code> only has a <code>1</code> in the &quot;ones&quot; column, the expression <code>attrs &amp; UserAttrs.Verified</code> will return <code>1</code> (the value of <code>UserAttrs.Verified</code>) if <code>attrs</code> has a <code>1</code> in the same column. It doesn't matter what <code>attrs</code> has in the other columns.</p> <p>As you probably know, bitwise operators aren't a TypeScript thing; this is one of the oldest computer science techniques for packing a bunch of data into less memory. Given that TypeScript is a pretty high-level language, we don't use this much. But it's cool that we have the option.</p> <h2 id=\"more-info\" tabindex=\"-1\">More Info</h2> <ul> <li><a href=\"https://stackoverflow.com/questions/39359740/what-are-enum-flags-in-typescript\">What are enum Flags in TypeScript?</a></li> <li><a href=\"https://basarat.gitbook.io/typescript/type-system/enums#number-enums-as-flags\">Number Enums as flags</a></li> <li><a href=\"https://learning.oreilly.com/library/view/effective-typescript/9781492053736/ch07.html\">Effective TypeScript, Chapter 7</a></li> </ul> ",
      "content_text": "I recently made a video about TypeScript Enums, and why you might not want to use them. But I want to go a little deeper on some seemingly strange enum behaviour. You might not expect this to be valid TypeScript: enum Role {   Executive = 0,   Manager = 1,   Engineer = 2 }  const myRole: Role = 3; But it is. We can assign a value that isn't part of Role to a variable of type Role. Why would TypeScript allow this? The reason seems to be supporting bit flags in TypeScript. The idea behind bit flags is that you can represent many boolean values in a single number, because that number can be represented in binary: 0 = 000 1 = 001 2 = 010 3 = 011 4 = 100 5 = 101 6 = 110 7 = 111 The first eight numbers (0 – 7) can all be represented as 3-digit binary numbers. In binary form, you can see how they can also represent all possible combinations of three boolean fields. The &quot;ones column&quot; represents the first boolean field, and so on. If we want a TypeScript enum that represents a set of three boolean fields, we only need three members in the enum: enum UserAttrs {   Verified = 1 &lt;&lt; 0, // 1   Active   = 1 &lt;&lt; 1, // 2   Paying   = 1 &lt;&lt; 2, // 4 } By convention, we're using the left-shift operator on 1 to set the values for these enum members. But we could have just as easily assigned the matching decimal numbers instead. When you left-shift 1, you're essentially choosing the column you want the binary 1 to be in. You can see how 1, 2, and 4 in the table above each have a single 1 in their respective columns. Now, we can use this enum to create different combinations of attributes: const verifiedAndActive = UserAttrs.Verified | UserAttrs.Active; // 3 = 011 const activeAndPaying = UserAttrs.Active | UserAttrs.Paying;     // 6 = 110 We're combining these attributes with the OR operator, and this works much like a union in a TypeScript type: you get a value that can be either side of the OR operator (or both sides, in our case!). And these new values can be treated as being the type UserAttrs. As I understand it, this is the main reason you can assign any number to an enum type in TypeScript: it could be a combination of actual members of the enum. Notice that in our new values, a 1 in the &quot;ones column&quot; represents a user who has verified=true, a 1 in the &quot;tens column&quot; represents a user who has active=true, etc. Now, you might wonder how we get the individual values out of our new combined values. Easy: use the AND operator: function isVerified(attrs: UserAttrs): boolean { \treturn (attrs &amp; UserAttrs.Verified) === UserAttrs.Verified; }  isVerified(activeAndPaying);   // false isVerified(verifiedAndActive); // true Again like in a TS type, the AND operator will give you anything that both sides share in common. Since UserAttrs.Verified only has a 1 in the &quot;ones&quot; column, the expression attrs &amp; UserAttrs.Verified will return 1 (the value of UserAttrs.Verified) if attrs has a 1 in the same column. It doesn't matter what attrs has in the other columns. As you probably know, bitwise operators aren't a TypeScript thing; this is one of the oldest computer science techniques for packing a bunch of data into less memory. Given that TypeScript is a pretty high-level language, we don't use this much. But it's cool that we have the option. More Info  What are enum Flags in TypeScript? Number Enums as flags Effective TypeScript, Chapter 7  ",
      "date_published": "2022-08-19T00:00:00.000Z",
      "tags": [
        "typescript",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/ts-private-properties/",
      "url": "https://shaky.sh/ts-private-properties/",
      "title": "TypeScript does not have private properties",
      "content_html": "<p>You might think that TypeScript allows you to have private properties in your classes:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">Foobar</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">private</span> mySecret<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>mySecret <span class=\"token operator\">=</span> <span class=\"token string\">\"hello\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>But remember, private properties aren't (yet) a feature of JavaScript. So this will transpile to the following code:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">Foobar</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>mySecret <span class=\"token operator\">=</span> <span class=\"token string\">\"hello\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>Nothing private about that property. It's easily accessible in JavaScript.</p> <p>It's not even that hard to get around in TypeScript:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">const</span> f <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Foobar</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>f <span class=\"token keyword\">as</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>mySecret<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// or, if you prefer</span></span> <span class=\"highlight-line\"><span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>f <span class=\"token keyword\">as</span> <span class=\"token builtin\">unknown</span> <span class=\"token keyword\">as</span> Record<span class=\"token operator\">&lt;</span><span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> <span class=\"token builtin\">unknown</span><span class=\"token operator\">></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>mySecret<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>I can't say I often run into the need for a private field, so I'm not exactly sure what the best practice is these days. But I'd probably reach for a closure:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">createFoobar</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">const</span> mySecret<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"hello\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token function\">getSecretLength</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">      <span class=\"token keyword\">return</span> mySecret<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>It's a fairly old pattern, but it still works great.</p> ",
      "content_text": "You might think that TypeScript allows you to have private properties in your classes: class Foobar {   private mySecret: string;    constructor() {     this.mySecret = \"hello\";   } } But remember, private properties aren't (yet) a feature of JavaScript. So this will transpile to the following code: class Foobar {     constructor() {         this.mySecret = \"hello\";     } } Nothing private about that property. It's easily accessible in JavaScript. It's not even that hard to get around in TypeScript: const f = new Foobar(); console.log((f as any).mySecret); // or, if you prefer console.log((f as unknown as Record&lt;string, unknown>).mySecret); I can't say I often run into the need for a private field, so I'm not exactly sure what the best practice is these days. But I'd probably reach for a closure: function createFoobar () {   const mySecret: string = \"hello\";    return {     getSecretLength() {       return mySecret.length;     }   } } It's a fairly old pattern, but it still works great. ",
      "date_published": "2022-08-22T00:00:00.000Z",
      "tags": [
        "typescript",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/ts-generic-utils/",
      "url": "https://shaky.sh/ts-generic-utils/",
      "title": "Better utility functions with TypeScript Generics",
      "content_html": "<p>This week I posted <a href=\"https://www.youtube.com/watch?v=t0qQSujSslQ\">a video about the basics of generics in TypeScript</a>. But I had to cut out one of my favourite ways to use generic parameters: flexible utility functions.</p> <p>It's pretty likely that there's some overlap in the various types in your system. A few examples:</p> <ul> <li>Types that represent persisted data (i.e. database records) have <code>id: string, createdAt: Date</code>.</li> <li>Types that represent people (<code>Employee</code>, <code>SupplierContact</code>) have <code>firstName: string, lastName: string</code>.</li> </ul> <p>Of course, we will have many utility functions to work on these types:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">User</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token comment\">// ...</span></span> <span class=\"highlight-line\">  createdAt<span class=\"token operator\">:</span> Date<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">getAge</span><span class=\"token punctuation\">(</span>u<span class=\"token operator\">:</span> User<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> u<span class=\"token punctuation\">.</span>createdAt<span class=\"token punctuation\">.</span><span class=\"token function\">valueOf</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>This <code>getAge</code> utility can only take <code>User</code> objects. But maybe we have a <code>Product</code> type that also has <code>createdAt</code>:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Product</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token comment\">// ...</span></span> <span class=\"highlight-line\">  createdAt<span class=\"token operator\">:</span> Date<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>Instead of creating a separate utility for getting the age of a product, we can change the argument type of the existing <code>getAge</code> function:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token comment\">// method 1</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">getAge</span><span class=\"token punctuation\">(</span>u<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> createdAt<span class=\"token operator\">:</span> Date <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> u<span class=\"token punctuation\">.</span>createdAt<span class=\"token punctuation\">.</span><span class=\"token function\">valueOf</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token comment\">// method 2</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">HasCreatedAt</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> createdAt<span class=\"token operator\">:</span> Date <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">getAge</span><span class=\"token punctuation\">(</span>u<span class=\"token operator\">:</span> HasCreatedAt<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> u<span class=\"token punctuation\">.</span>createdAt<span class=\"token punctuation\">.</span><span class=\"token function\">valueOf</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>You can do this inline or with a type alias, doesn't matter because TypeScript is structural. Either way, you can now use <code>getAge</code> with both a <code>User</code> and a <code>Product</code>, because both satisfy the function's constraint.</p> <p>Now, let's say you want to create a utility function for adding <code>age</code> to the argument: maybe this is part of the hydration step in your REST API. Something that works just for <code>User</code> might look like this:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">addAge</span><span class=\"token punctuation\">(</span>u<span class=\"token operator\">:</span> User<span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> User <span class=\"token operator\">&amp;</span> <span class=\"token punctuation\">{</span> age<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span> <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">      <span class=\"token operator\">...</span>u<span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">      age<span class=\"token operator\">:</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> u<span class=\"token punctuation\">.</span>createdAt<span class=\"token punctuation\">.</span><span class=\"token function\">valueOf</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>To make this work for <code>Product</code> as well, we need to use a <strong>generic parameter</strong> in our function:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">HasCreatedAt</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> createdAt<span class=\"token operator\">:</span> Date <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">HasAge</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> age<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token comment\">// method 1</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token generic-function\"><span class=\"token function\">addAge</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span>u<span class=\"token operator\">:</span> <span class=\"token constant\">T</span> <span class=\"token operator\">&amp;</span> HasCreatedAt<span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span> <span class=\"token operator\">&amp;</span> HasAge <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">      <span class=\"token operator\">...</span>u<span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">      age<span class=\"token operator\">:</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> u<span class=\"token punctuation\">.</span>createdAt<span class=\"token punctuation\">.</span><span class=\"token function\">valueOf</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token comment\">// method 2</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token generic-function\"><span class=\"token function\">addAge</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> HasCreatedAt<span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span>u<span class=\"token operator\">:</span> <span class=\"token constant\">T</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span> <span class=\"token operator\">&amp;</span> HasAge <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">      <span class=\"token operator\">...</span>u<span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">      age<span class=\"token operator\">:</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> u<span class=\"token punctuation\">.</span>createdAt<span class=\"token punctuation\">.</span><span class=\"token function\">valueOf</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>Now, <code>addAge</code> will take any <code>T</code> as long as it includes a <code>createdAt: Date</code> field. And, it will return the same shape with an additional <code>age: number</code> field. Perfect for both <code>User</code> and <code>Product</code>.</p> <p>I'm sure you can think of several places where generic utilities like this can reduce the amount of code you have to write. One case that I've run into recently is refactoring. When refactoring a system, you might have <code>UserOld</code> and <code>UserNew</code> types, which has some overlap. You can likely introduce generic parameters into any old utilities you have, so they can work for your new types as well.</p> ",
      "content_text": "This week I posted a video about the basics of generics in TypeScript. But I had to cut out one of my favourite ways to use generic parameters: flexible utility functions. It's pretty likely that there's some overlap in the various types in your system. A few examples:  Types that represent persisted data (i.e. database records) have id: string, createdAt: Date. Types that represent people (Employee, SupplierContact) have firstName: string, lastName: string.  Of course, we will have many utility functions to work on these types: type User = {   // ...   createdAt: Date; }  function getAge(u: User) {   return Date.now() - u.createdAt.valueOf(); } This getAge utility can only take User objects. But maybe we have a Product type that also has createdAt: type Product = {   // ...   createdAt: Date; } Instead of creating a separate utility for getting the age of a product, we can change the argument type of the existing getAge function: // method 1 function getAge(u: { createdAt: Date }) {   return Date.now() - u.createdAt.valueOf(); }  // method 2 type HasCreatedAt = { createdAt: Date };  function getAge(u: HasCreatedAt) {   return Date.now() - u.createdAt.valueOf(); } You can do this inline or with a type alias, doesn't matter because TypeScript is structural. Either way, you can now use getAge with both a User and a Product, because both satisfy the function's constraint. Now, let's say you want to create a utility function for adding age to the argument: maybe this is part of the hydration step in your REST API. Something that works just for User might look like this: function addAge(u: User): User &amp; { age: number } {   return {       ...u,       age: Date.now() - u.createdAt.valueOf()     }; } To make this work for Product as well, we need to use a generic parameter in our function: type HasCreatedAt = { createdAt: Date }; type HasAge = { age: number };  // method 1 function addAge&lt;T>(u: T &amp; HasCreatedAt): T &amp; HasAge {   return {       ...u,       age: Date.now() - u.createdAt.valueOf()     }; }  // method 2 function addAge&lt;T extends HasCreatedAt>(u: T): T &amp; HasAge {   return {       ...u,       age: Date.now() - u.createdAt.valueOf();     }; } Now, addAge will take any T as long as it includes a createdAt: Date field. And, it will return the same shape with an additional age: number field. Perfect for both User and Product. I'm sure you can think of several places where generic utilities like this can reduce the amount of code you have to write. One case that I've run into recently is refactoring. When refactoring a system, you might have UserOld and UserNew types, which has some overlap. You can likely introduce generic parameters into any old utilities you have, so they can work for your new types as well. ",
      "date_published": "2022-09-20T00:00:00.000Z",
      "tags": [
        "typescript",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/tools/",
      "url": "https://shaky.sh/tools/",
      "title": "My Daily Tools",
      "content_html": "<p>This week I posted <a href=\"https://youtu.be/2Cq_prRzdX8\">a video about the tools I use daily as a software engineer</a>. This is a convenient place to see a list of all those tools, as well as find links to other places where I've talked about them more.</p> <h2 id=\"alacritty\" tabindex=\"-1\">Alacritty</h2> <p><a href=\"https://alacritty.org/\">Alacritty</a> is the terminal emulator I use.</p> <ul> <li><a href=\"https://github.com/andrew8088/dotfiles/blob/main/alacritty/alacritty.yml\">My Alacritty config</a></li> </ul> <h2 id=\"zsh\" tabindex=\"-1\">zsh</h2> <p>Nothing special here, no OMZ or anything, just some basic config.</p> <ul> <li><a href=\"https://github.com/andrew8088/dotfiles/blob/main/zsh/rc.zsh\">My ZSH config</a></li> <li><a href=\"https://youtu.be/5oXy6ktYs7I\">Video: How I organize my dotfiles</a></li> <li><a href=\"https://youtu.be/-GUXwL7ZoXo\">Video: Creating shell aliases</a></li> <li><a href=\"https://youtu.be/DJR5RLVOjOw\">Video: 11 shell aliases you'll use today</a></li> </ul> <h2 id=\"starship-prompt\" tabindex=\"-1\">Starship Prompt</h2> <p><a href=\"https://starship.rs/\">Starship</a> is a easy-to-customize prompt for whatever shell you use.</p> <ul> <li><a href=\"https://github.com/andrew8088/dotfiles/blob/main/starship/starship.toml\">My Starship config</a></li> <li><a href=\"https://youtu.be/xTJzJ-_vdag\">Video: Painless prompt setup with Starship</a></li> <li><a href=\"https://youtu.be/VgTu1_92U0U\">Video: Building custom modules for starship prompt</a></li> </ul> <h2 id=\"z\" tabindex=\"-1\">z</h2> <p>A better alternative to <code>cd</code>, you can get this with <code>brew install z</code> on MacOS. If you're on another OS, it's available there too. Or just get the shell script from the link below.</p> <ul> <li><a href=\"https://github.com/rupa/z\">GitHub: rupa/z</a></li> </ul> <h2 id=\"fzf\" tabindex=\"-1\">fzf</h2> <p>So many uses for <code>fzf</code>, but I use it mainly for shell history searching (ctrl-r).</p> <ul> <li><a href=\"https://github.com/junegunn/fzf\">GitHub: junegunn/fzf</a></li> </ul> <h2 id=\"neovim-%2F-lunarvim\" tabindex=\"-1\">Neovim / LunarVim</h2> <p><a href=\"https://neovim.io/\">Neovim</a> is a modern rewrite of Vim. <a href=\"https://www.lunarvim.org/\">LunarVim</a> is an opinionated config set for Neovim.</p> <ul> <li><a href=\"https://github.com/andrew8088/dotfiles/blob/main/lvim/config.lua\">My LunarVim config</a></li> </ul> <h2 id=\"bonus%3A-tmux\" tabindex=\"-1\">Bonus: Tmux</h2> <p>I totally forgot to mention <a href=\"https://github.com/tmux/tmux\">tmux</a> in the video, but I use it daily as well! Often, I just use it as a fast way to have multiple sessions open at once.</p> <ul> <li><a href=\"https://shaky.sh/why-tmux/\">Post: Why I use tmux</a></li> </ul> ",
      "content_text": "This week I posted a video about the tools I use daily as a software engineer. This is a convenient place to see a list of all those tools, as well as find links to other places where I've talked about them more. Alacritty Alacritty is the terminal emulator I use.  My Alacritty config  zsh Nothing special here, no OMZ or anything, just some basic config.  My ZSH config Video: How I organize my dotfiles Video: Creating shell aliases Video: 11 shell aliases you'll use today  Starship Prompt Starship is a easy-to-customize prompt for whatever shell you use.  My Starship config Video: Painless prompt setup with Starship Video: Building custom modules for starship prompt  z A better alternative to cd, you can get this with brew install z on MacOS. If you're on another OS, it's available there too. Or just get the shell script from the link below.  GitHub: rupa/z  fzf So many uses for fzf, but I use it mainly for shell history searching (ctrl-r).  GitHub: junegunn/fzf  Neovim / LunarVim Neovim is a modern rewrite of Vim. LunarVim is an opinionated config set for Neovim.  My LunarVim config  Bonus: Tmux I totally forgot to mention tmux in the video, but I use it daily as well! Often, I just use it as a fast way to have multiple sessions open at once.  Post: Why I use tmux  ",
      "date_published": "2023-01-09T00:00:00.000Z",
      "tags": [
        "tech",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/encrypting-files-in-git/",
      "url": "https://shaky.sh/encrypting-files-in-git/",
      "title": "Encrypting Files in Git",
      "content_html": "<p>I've been doing <a href=\"https://plaintextaccounting.org/\">plain-text accounting</a> for about 8 months; so, I often find myself copying transactions out of my online bank statement and into a text editor. In an effort to improve this process, I wrote a script.</p> <p>My script does several things:</p> <ul> <li>Formats each transaction</li> <li>Removes unneeded data, retail location IDs or POS-system tags</li> <li>Labels common transactions with the correct labels</li> </ul> <p>Usually I'd put a script like this in my <a href=\"https://github.com/andrew8088/dotfiles\">dotfiles repo</a>, but this time I wasn't so sure. The script includes the names of a few places (cities and stores) that I regularly visit, and my dotfiles repo is public. So I didn't want to commit this script for everyone to see. But I did need to share it across several of my machines.</p> <p>My simple (and I do mean simple) solution was to use <code>gpg</code> to encrypt the file. If you're on MacOS like I am, you can install it via <code>brew install gpg</code>. Then, it's easy to encrypt the file:</p> <pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"highlight-line\"><span class=\"token operator\">></span> gpg <span class=\"token parameter variable\">-c</span> my-script.js</span></code></pre> <p>You'll be asked to enter a password twice; I used 1Password to generate and store a secure password, and then pasted it in. The result is a new, encrypted file that you can commit. I added the main script to my <code>.gitignore</code> file to be safe:</p> <pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"highlight-line\">my-script.js <span class=\"token punctuation\">(</span>gitignore this one<span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">my-scrupt.js.gpg <span class=\"token punctuation\">(</span>commit this one<span class=\"token punctuation\">)</span></span></code></pre> <p>Then, on my other machine, I can decrypt it with this command:</p> <pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"highlight-line\"><span class=\"token operator\">></span> gpg my-script.js.gpg</span></code></pre> <p>This feels like a light-weight way to easily and securely version control scripts that I'd like to keep private.</p> <p>A fun next step here would be to integrate the 1Password CLI, so maybe I'll try that soon.</p> ",
      "content_text": "I've been doing plain-text accounting for about 8 months; so, I often find myself copying transactions out of my online bank statement and into a text editor. In an effort to improve this process, I wrote a script. My script does several things:  Formats each transaction Removes unneeded data, retail location IDs or POS-system tags Labels common transactions with the correct labels  Usually I'd put a script like this in my dotfiles repo, but this time I wasn't so sure. The script includes the names of a few places (cities and stores) that I regularly visit, and my dotfiles repo is public. So I didn't want to commit this script for everyone to see. But I did need to share it across several of my machines. My simple (and I do mean simple) solution was to use gpg to encrypt the file. If you're on MacOS like I am, you can install it via brew install gpg. Then, it's easy to encrypt the file: > gpg -c my-script.js You'll be asked to enter a password twice; I used 1Password to generate and store a secure password, and then pasted it in. The result is a new, encrypted file that you can commit. I added the main script to my .gitignore file to be safe: my-script.js (gitignore this one) my-scrupt.js.gpg (commit this one) Then, on my other machine, I can decrypt it with this command: > gpg my-script.js.gpg This feels like a light-weight way to easily and securely version control scripts that I'd like to keep private. A fun next step here would be to integrate the 1Password CLI, so maybe I'll try that soon. ",
      "date_published": "2023-04-04T00:00:00.000Z",
      "tags": [
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/throttle-debounce/",
      "url": "https://shaky.sh/throttle-debounce/",
      "title": "Throttle vs. Debounce",
      "content_html": "<p>This might just be me, but I confuse <code>debounce</code> and <code>throttle</code>. I can never remember the difference. This post should help me remember the difference.</p> <h2 id=\"neither\" tabindex=\"-1\">Neither</h2> <p>Every <code>mousemove</code> event on the <code>div</code> below increments the counter:</p> <div id=\"setup-el\" onmousemove=\"setupFn()\" style=\"border:1px solid black;\"> <div>Neither: triggered <span>0</span> times</div> </div> <h2 id=\"throttle\" tabindex=\"-1\">Throttle</h2> <pre class=\"language-js\"><code class=\"language-js\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">throttle</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">fn<span class=\"token punctuation\">,</span> ms</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">let</span> id<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">        id <span class=\"token operator\">=</span> <span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">            <span class=\"token function\">fn</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">            id <span class=\"token operator\">=</span> <span class=\"token keyword\">undefined</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> ms<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>When using <code>throttle</code>, your function will run <em>at most</em> once per interval, no matter how many times it is triggered in that interval.</p> <div id=\"throttle-el\" onmousemove=\"throttleFn()\" style=\"border:1px solid black;\"> <div>Throttle 200ms: triggered <span>0</span> times</div> </div> <h2 id=\"debounce\" tabindex=\"-1\">Debounce</h2> <pre class=\"language-js\"><code class=\"language-js\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">debounce</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">fn<span class=\"token punctuation\">,</span> ms</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">let</span> id<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span> <span class=\"token function\">clearTimeout</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">        id <span class=\"token operator\">=</span> <span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span>fn<span class=\"token punctuation\">,</span> ms<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>When using <code>debounce</code>, your function will run after it has not been triggered for a full interval.</p> <div id=\"debounce-el\" onmousemove=\"debounceFn()\" style=\"border:1px solid black;\"> <div>Debounce 200ms: triggered <span>0</span> times</div> </div> <script> const setupEl = document.querySelector(\"#setup-el span\"); const debounceEl = document.querySelector(\"#debounce-el span\"); const throttleEl = document.querySelector(\"#throttle-el span\");  let setupI = 0; const setupFn = () => {     setupEl.innerText = ++setupI; };  let debounceI = 0; const debounceFn = debounce(() => {     debounceEl.innerText = ++debounceI; }, 200);  let throttleI = 0; const throttleFn = throttle(() => {     throttleEl.innerText = ++throttleI; }, 200);  function debounce(fn, ms) {     let id;     return () => {         if (id) clearTimeout(id);         id = setTimeout(fn, ms);     }; }  function throttle(fn, ms) {     let id;     return () => {         if (id) return;         id = setTimeout(() => {             fn();             id = undefined;         }, ms);     }; } </script> ",
      "content_text": "This might just be me, but I confuse debounce and throttle. I can never remember the difference. This post should help me remember the difference. Neither Every mousemove event on the div below increments the counter:  Neither: triggered 0 times  Throttle function throttle(fn, ms) {     let id;     return () => {         if (id) return;         id = setTimeout(() => {             fn();             id = undefined;         }, ms);     }; } When using throttle, your function will run at most once per interval, no matter how many times it is triggered in that interval.  Throttle 200ms: triggered 0 times  Debounce function debounce(fn, ms) {     let id;     return () => {         if (id) clearTimeout(id);         id = setTimeout(fn, ms);     }; } When using debounce, your function will run after it has not been triggered for a full interval.  Debounce 200ms: triggered 0 times   const setupEl = document.querySelector(\"#setup-el span\"); const debounceEl = document.querySelector(\"#debounce-el span\"); const throttleEl = document.querySelector(\"#throttle-el span\");  let setupI = 0; const setupFn = () => {     setupEl.innerText = ++setupI; };  let debounceI = 0; const debounceFn = debounce(() => {     debounceEl.innerText = ++debounceI; }, 200);  let throttleI = 0; const throttleFn = throttle(() => {     throttleEl.innerText = ++throttleI; }, 200);  function debounce(fn, ms) {     let id;     return () => {         if (id) clearTimeout(id);         id = setTimeout(fn, ms);     }; }  function throttle(fn, ms) {     let id;     return () => {         if (id) return;         id = setTimeout(() => {             fn();             id = undefined;         }, ms);     }; }  ",
      "date_published": "2023-05-02T00:00:00.000Z",
      "tags": [
        "javascript",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/ts-distributive-conditional-types/",
      "url": "https://shaky.sh/ts-distributive-conditional-types/",
      "title": "ELI5 Distributive Conditional Types in TypeScript",
      "content_html": "<p>Update: <a href=\"https://www.youtube.com/watch?v=JyUwtRuMKUk\">video with the same content</a></p> <p>I've been aware of <strong>distributive conditional types</strong> in TypeScript for a while, but recently, finally, I figured out how they work. As much as I love TS, the docs often leave something to be desired, and that's definitely the case for <a href=\"https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types\">distributive conditional types</a>.</p> <p>So I have two goals with this post:</p> <ol> <li>Write the ELI5 docs that I needed a few weeks ago</li> <li>Solicit corrections where I'm wrong</li> </ol> <hr> <p>Behold, a simple union:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">ASimpleUnion</span> <span class=\"token operator\">=</span> <span class=\"token builtin\">string</span> <span class=\"token operator\">|</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Let's start with something obvious: there's no difference between the type alias of a union and the &quot;union literal&quot; (is that a term?) when using them as a generic argument:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\"><span class=\"token constant\">A1</span></span> <span class=\"token operator\">=</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span>ASimpleUnion<span class=\"token operator\">></span></span> <span class=\"highlight-line\"><span class=\"token comment\">// same as</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\"><span class=\"token constant\">A2</span></span> <span class=\"token operator\">=</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span><span class=\"token builtin\">string</span> <span class=\"token operator\">|</span> <span class=\"token builtin\">number</span><span class=\"token operator\">></span></span></code></pre> <p>Both versions are the same shape: an array that can include strings and numbers.</p> <p>So, what if, instead of transforming <code>ASimpleUnion</code> into an array of strings and numbers (as we do above with <code>A2</code>), we want to transform it into a union of either an array of strings or an array of numbers, like <code>A3</code> below?</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\"><span class=\"token constant\">A3</span></span> <span class=\"token operator\">=</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span><span class=\"token builtin\">string</span><span class=\"token operator\">></span> <span class=\"token operator\">|</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span><span class=\"token builtin\">number</span><span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span></code></pre> <p>To create <code>A3</code>, we need to <strong>distribute</strong> the <code>string | number</code> union. Essentially, we're &quot;iterating&quot; over the members of the union, transforming each member into a new type, and then &quot;union-ing&quot; them back together.</p> <p>This is where distributive conditional types come into play. To trigger the distribution of a union, we can use the one-two-punch of a <strong>generic argument</strong> and a <strong>conditional type</strong>. Both of those mechanics are important. Here's an example that lays it out.</p> <h2 id=\"how-generics-%26-conditional-types-work-together\" tabindex=\"-1\">How Generics &amp; Conditional Types Work Together</h2> <p>(Bear with my contrived examples: a practical one is coming up next. The super-basic examples help me focus on behaviour of the TypeScript mechanics here.)</p> <p>Let's start with a union of a few string constants and <code>undefined</code>:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">AnotherUnion</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"one\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"two\"</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">undefined</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"three\"</span><span class=\"token punctuation\">;</span></span></code></pre> <p>As we've seen earlier, if we use <code>AnotherUnion</code> as a generic argument, it's treated as a single &quot;unit&quot;, literally an alias:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\"><span class=\"token constant\">T</span></span> <span class=\"token operator\">=</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span>AnotherUnion<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// Array&lt;\"one\" | \"two\" | undefined | \"three\"></span></span></code></pre> <p>Then, if we use <code>AnotherUnion</code> in the condition of a conditional type, it's also treated as a type alias:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\"><span class=\"token constant\">T</span></span> <span class=\"token operator\">=</span> AnotherUnion <span class=\"token keyword\">extends</span> <span class=\"token class-name\"><span class=\"token builtin\">string</span></span> <span class=\"token operator\">?</span> AnotherUnion <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// never;</span></span></code></pre> <p>Here, <code>AnotherUnion</code> doesn't extend <code>string</code> (because it includes <code>undefined</code>), so <code>T</code> results in <code>never</code>.</p> <p>But when we use these two TS mechanics together, we can <strong>distribute</strong> the union:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">OnlyStrings<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span></span> <span class=\"token operator\">=</span> <span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\"><span class=\"token builtin\">string</span></span> <span class=\"token operator\">?</span> <span class=\"token constant\">T</span> <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\"><span class=\"token constant\">T</span></span> <span class=\"token operator\">=</span> OnlyStrings<span class=\"token operator\">&lt;</span>AnotherUnion<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// \"one\" | \"two\" | \"three\"</span></span></code></pre> <p>We combine the use of a generic argument with the conditional type, and the result is that <code>T</code> is a union of only the strings in <code>AnotherUnion</code>. Each member of <code>AnotherUnion</code> was individually tested in the <code>T extends string</code> condition, and the resulting type is the union of each individual conditional check. In this case, we've essentially filtered our original union.</p> <h2 id=\"non-filtering-examples\" tabindex=\"-1\">Non-Filtering Examples</h2> <p>Using a conditional type for filtering feels pretty natural. But that's not always what we want to do. Remember our earlier question:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token comment\">// how do we convert this:</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">ASimpleUnion</span> <span class=\"token operator\">=</span> <span class=\"token builtin\">string</span> <span class=\"token operator\">|</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// to this:</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\"><span class=\"token constant\">A3</span></span> <span class=\"token operator\">=</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span><span class=\"token builtin\">string</span><span class=\"token operator\">></span> <span class=\"token operator\">|</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span><span class=\"token builtin\">number</span><span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span></code></pre> <p>Well, we want to distribute our union, so let's use both a generic argument and a conditional type:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">ToArray<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span></span> <span class=\"token operator\">=</span> <span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\"><span class=\"token constant\">T</span></span> <span class=\"token operator\">?</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\"><span class=\"token constant\">A4</span></span> <span class=\"token operator\">=</span> ToArray<span class=\"token operator\">&lt;</span>ASimpleUnion<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// Array&lt;string> | Array&lt;number></span></span></code></pre> <p>Okay ... but what's up with <code>T extends T</code>? Well, the actual condition doesn't really matter here, it's just the mechanism TypeScript uses (along with the generic argument) to trigger the union distribution. If we want to avoid filtering out any of the members of our union, we need to use an always-true condition. <code>T extends T</code> is a popular one, since every element of <code>T</code> is (obviously) in the set of all values in <code>T</code>.</p> <p>(<code>T extends any</code> is also popular, but I tend to avoid <code>any</code>, and I think <code>T extends T</code> gives me just enough pause to recognize that this isn't a &quot;normal&quot; conditional.)</p> <h2 id=\"how-to-avoid-distributing-a-union\" tabindex=\"-1\">How to avoid distributing a union</h2> <p>What if you need to use a union with a generic argument and a conditional type, but you <strong>don't</strong> want to trigger distribution? The right mechanic to use is wrapping both sides of your conditional expression (both <code>T</code> in our case) in a tuple. We can tweak the last example to see this in action:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">ToArray<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token constant\">T</span><span class=\"token punctuation\">]</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">[</span><span class=\"token constant\">T</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">?</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span> <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\"><span class=\"token constant\">A4</span></span> <span class=\"token operator\">=</span> ToArray<span class=\"token operator\">&lt;</span>ASimpleUnion<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// Array&lt;string | number></span></span></code></pre> <p>Again, a contrived example, but it shows the mechanic in action.</p> <h2 id=\"a-practical-example-of-distributing-a-union\" tabindex=\"-1\">A Practical Example of Distributing a Union</h2> <p>Here we have various form element response shapes:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">CheckboxResponse</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">\tid<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">\ttype<span class=\"token operator\">:</span> <span class=\"token string\">\"checkbox\"</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">\tvalue<span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">TextResponse</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">\tid<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">\ttype<span class=\"token operator\">:</span> <span class=\"token string\">\"text\"</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">\tvalue<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">FormResponse</span> <span class=\"token operator\">=</span> CheckboxResponse <span class=\"token operator\">|</span> TextResponse<span class=\"token punctuation\">;</span></span></code></pre> <p>Notice specifically that we have a strong correlation between the <code>type</code> and <code>value</code> fields, which is great when narrowing <code>FormResponse</code>. But now let's omit the <code>id</code> field:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">RenderedFormResponse</span> <span class=\"token operator\">=</span> Omit<span class=\"token operator\">&lt;</span>FormResponse<span class=\"token punctuation\">,</span> <span class=\"token string\">'id'</span><span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// {</span></span> <span class=\"highlight-line\"><span class=\"token comment\">//   type: \"checkbox\" | \"text\";</span></span> <span class=\"highlight-line\"><span class=\"token comment\">//   value: string | boolean;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// }</span></span></code></pre> <p>Before learning all this, I would have expected <code>RenderedFormResponse</code> to be the same union shape, just without the <code>id</code> fields in each member of the union. However, if we take a look at the implementation of <code>Omit</code> below, we can see that it uses a generic argument, but no condition, so there's no distribution:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Omit<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">K</span> <span class=\"token keyword\">extends</span> <span class=\"token builtin\">string</span> <span class=\"token operator\">|</span> <span class=\"token builtin\">number</span> <span class=\"token operator\">|</span> <span class=\"token builtin\">symbol</span><span class=\"token operator\">></span></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">\t<span class=\"token punctuation\">[</span><span class=\"token constant\">P</span> <span class=\"token keyword\">in</span> Exclude<span class=\"token operator\">&lt;</span><span class=\"token keyword\">keyof</span> <span class=\"token constant\">T</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">K</span><span class=\"token operator\">></span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span><span class=\"token punctuation\">[</span><span class=\"token constant\">P</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>It's also a mapped type, and the effect of mapping over a non-distributed union is that it's &quot;flattened.&quot; We've lost the link between the <code>type</code> field and the <code>value</code> field.</p> <p>We can solve this pretty simply: wrap <code>Omit</code> in a type that includes a condition, to trigger the distribution:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">DistributiveOmit<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">K</span> <span class=\"token keyword\">extends</span> <span class=\"token builtin\">string</span><span class=\"token operator\">></span></span> <span class=\"token operator\">=</span> <span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\"><span class=\"token constant\">T</span></span> <span class=\"token operator\">?</span> Omit<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">K</span><span class=\"token operator\">></span> <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">RenderedResponse</span> <span class=\"token operator\">=</span> DistributiveOmit<span class=\"token operator\">&lt;</span>FormResponse<span class=\"token punctuation\">,</span> <span class=\"token string\">'id'</span><span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// Omit&lt;CheckboxFormResponse, \"id\"> | Omit&lt;TextFormResponse, \"id\"></span></span></code></pre> <h2 id=\"wrap-up\" tabindex=\"-1\">Wrap Up</h2> <p>If you browse through the types in popular libraries, you'll more than likely see distributivity in practice. For example, in <a href=\"https://github.com/DefinitelyTyped/DefinitelyTyped/blob/013222a1262cc0cb3a49515209c6db03c0e4b245/types/react/index.d.ts#L810\">the React type definitions</a>, you can see a specific case: a type that omits the <code>ref</code> prop from a component prop types.</p> <p>If you have other practical examples if distributive conditional types at work, I'd love to see them! Also, if I got something wrong here, let me know!</p> ",
      "content_text": "Update: video with the same content I've been aware of distributive conditional types in TypeScript for a while, but recently, finally, I figured out how they work. As much as I love TS, the docs often leave something to be desired, and that's definitely the case for distributive conditional types. So I have two goals with this post:  Write the ELI5 docs that I needed a few weeks ago Solicit corrections where I'm wrong   Behold, a simple union: type ASimpleUnion = string | number; Let's start with something obvious: there's no difference between the type alias of a union and the &quot;union literal&quot; (is that a term?) when using them as a generic argument: type A1 = Array&lt;ASimpleUnion> // same as type A2 = Array&lt;string | number> Both versions are the same shape: an array that can include strings and numbers. So, what if, instead of transforming ASimpleUnion into an array of strings and numbers (as we do above with A2), we want to transform it into a union of either an array of strings or an array of numbers, like A3 below? type A3 = Array&lt;string> | Array&lt;number>; To create A3, we need to distribute the string | number union. Essentially, we're &quot;iterating&quot; over the members of the union, transforming each member into a new type, and then &quot;union-ing&quot; them back together. This is where distributive conditional types come into play. To trigger the distribution of a union, we can use the one-two-punch of a generic argument and a conditional type. Both of those mechanics are important. Here's an example that lays it out. How Generics &amp; Conditional Types Work Together (Bear with my contrived examples: a practical one is coming up next. The super-basic examples help me focus on behaviour of the TypeScript mechanics here.) Let's start with a union of a few string constants and undefined: type AnotherUnion = \"one\" | \"two\" | undefined | \"three\"; As we've seen earlier, if we use AnotherUnion as a generic argument, it's treated as a single &quot;unit&quot;, literally an alias: type T = Array&lt;AnotherUnion>; // Array&lt;\"one\" | \"two\" | undefined | \"three\"> Then, if we use AnotherUnion in the condition of a conditional type, it's also treated as a type alias: type T = AnotherUnion extends string ? AnotherUnion : never; // never; Here, AnotherUnion doesn't extend string (because it includes undefined), so T results in never. But when we use these two TS mechanics together, we can distribute the union: type OnlyStrings&lt;T> = T extends string ? T : never;  type T = OnlyStrings&lt;AnotherUnion>; // \"one\" | \"two\" | \"three\" We combine the use of a generic argument with the conditional type, and the result is that T is a union of only the strings in AnotherUnion. Each member of AnotherUnion was individually tested in the T extends string condition, and the resulting type is the union of each individual conditional check. In this case, we've essentially filtered our original union. Non-Filtering Examples Using a conditional type for filtering feels pretty natural. But that's not always what we want to do. Remember our earlier question: // how do we convert this: type ASimpleUnion = string | number; // to this: type A3 = Array&lt;string> | Array&lt;number>; Well, we want to distribute our union, so let's use both a generic argument and a conditional type: type ToArray&lt;T> = T extends T ? Array&lt;T> : never;  type A4 = ToArray&lt;ASimpleUnion>; // Array&lt;string> | Array&lt;number> Okay ... but what's up with T extends T? Well, the actual condition doesn't really matter here, it's just the mechanism TypeScript uses (along with the generic argument) to trigger the union distribution. If we want to avoid filtering out any of the members of our union, we need to use an always-true condition. T extends T is a popular one, since every element of T is (obviously) in the set of all values in T. (T extends any is also popular, but I tend to avoid any, and I think T extends T gives me just enough pause to recognize that this isn't a &quot;normal&quot; conditional.) How to avoid distributing a union What if you need to use a union with a generic argument and a conditional type, but you don't want to trigger distribution? The right mechanic to use is wrapping both sides of your conditional expression (both T in our case) in a tuple. We can tweak the last example to see this in action: type ToArray&lt;T> = [T] extends [T] ? Array&lt;T> : never;  type A4 = ToArray&lt;ASimpleUnion>; // Array&lt;string | number> Again, a contrived example, but it shows the mechanic in action. A Practical Example of Distributing a Union Here we have various form element response shapes: type CheckboxResponse = { \tid: string; \ttype: \"checkbox\", \tvalue: boolean, };  type TextResponse = { \tid: string; \ttype: \"text\", \tvalue: string, }  type FormResponse = CheckboxResponse | TextResponse; Notice specifically that we have a strong correlation between the type and value fields, which is great when narrowing FormResponse. But now let's omit the id field: type RenderedFormResponse = Omit&lt;FormResponse, 'id'>; // { //   type: \"checkbox\" | \"text\"; //   value: string | boolean; // } Before learning all this, I would have expected RenderedFormResponse to be the same union shape, just without the id fields in each member of the union. However, if we take a look at the implementation of Omit below, we can see that it uses a generic argument, but no condition, so there's no distribution: type Omit&lt;T, K extends string | number | symbol> = { \t[P in Exclude&lt;keyof T, K>]: T[P]; } It's also a mapped type, and the effect of mapping over a non-distributed union is that it's &quot;flattened.&quot; We've lost the link between the type field and the value field. We can solve this pretty simply: wrap Omit in a type that includes a condition, to trigger the distribution: type DistributiveOmit&lt;T, K extends string> = T extends T ? Omit&lt;T, K> : never;  type RenderedResponse = DistributiveOmit&lt;FormResponse, 'id'>; // Omit&lt;CheckboxFormResponse, \"id\"> | Omit&lt;TextFormResponse, \"id\"> Wrap Up If you browse through the types in popular libraries, you'll more than likely see distributivity in practice. For example, in the React type definitions, you can see a specific case: a type that omits the ref prop from a component prop types. If you have other practical examples if distributive conditional types at work, I'd love to see them! Also, if I got something wrong here, let me know! ",
      "date_published": "2023-05-03T00:00:00.000Z",
      "tags": [
        "typescript",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/promise-with-resolvers/",
      "url": "https://shaky.sh/promise-with-resolvers/",
      "title": "Promise.withResolvers in JavaScript",
      "content_html": "<p>I recently <a href=\"https://youtu.be/Yvhad4zdPqI\">made a video</a> about the deferred promise pattern in JavaScript. If you aren't familiar, the code is pretty simple:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">Deferred<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">E</span> <span class=\"token operator\">=</span> <span class=\"token builtin\">unknown</span><span class=\"token operator\">></span></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  promise<span class=\"token operator\">:</span> <span class=\"token builtin\">Promise</span><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token function-variable function\">resolve</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>value<span class=\"token operator\">:</span> <span class=\"token constant\">T</span> <span class=\"token operator\">|</span> PromiseLike<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function-variable function\">void</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token function-variable function\">reject</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>reason<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token constant\">E</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function-variable function\">void</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>promise <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\"><span class=\"token builtin\">Promise</span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>resolve<span class=\"token punctuation\">,</span> reject<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>resolve <span class=\"token operator\">=</span> resolve<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>reject <span class=\"token operator\">=</span> reject<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>I think of this as a kind of &quot;inverted promise&quot;, where you can access the <code>resolve</code> and <code>reject</code> functions from outside the promise callback.</p> <p>This is a useful enough pattern that it will soon be part of the Promise API! <a href=\"https://github.com/alexandercerutti\">Alexander Cerutti</a> pointed me to a <a href=\"https://github.com/tc39/proposal-promise-with-resolvers\">TC39 Proposal for <code>Promise.withResolvers</code></a> that has made it to stage 3. Using that signature, we could rewrite the above code like this:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token generic-function\"><span class=\"token function\">withResolvers</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">let</span> <span class=\"token function-variable function\">resolve</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>value<span class=\"token operator\">:</span> <span class=\"token constant\">T</span> <span class=\"token operator\">|</span> PromiseLike<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function-variable function\">void</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">let</span> <span class=\"token function-variable function\">reject</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>reason<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">unknown</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function-variable function\">void</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token keyword\">const</span> promise <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\"><span class=\"token builtin\">Promise</span><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>_resolve<span class=\"token punctuation\">,</span> _reject<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    resolve <span class=\"token operator\">=</span> _resolve<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    reject <span class=\"token operator\">=</span> _reject<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> resolve<span class=\"token punctuation\">,</span> reject<span class=\"token punctuation\">,</span> promise <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Same rose, another name.</p> <p>So, where is this pattern useful? Here are a few examples that I've run into before.</p> <h2 id=\"event-based-apis\" tabindex=\"-1\">Event-based APIs</h2> <p>A lot of the web APIs or Node APIs are event-based, which can mean a typical pattern of doing everything inside a <code>Promise</code> callback just isn't ergonomic. Using the deferred pattern can keep your code clean and functional:</p> <p>In this example, I'm using the Web audio APIs to record (via <code>MediaRecorder</code>) audio from a <code>MediaStream</code> and into a <code>Blob</code>:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">recordStreamAsBlob</span><span class=\"token punctuation\">(</span>stream<span class=\"token operator\">:</span> MediaStream<span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token builtin\">Promise</span><span class=\"token operator\">&lt;</span>Blob<span class=\"token operator\">></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">const</span> mediaRecorder <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">MediaRecorder</span><span class=\"token punctuation\">(</span>stream<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token keyword\">const</span> chunks<span class=\"token operator\">:</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span>BlobPart<span class=\"token operator\">></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">const</span> deferredBlob <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Deferred<span class=\"token operator\">&lt;</span>Blob<span class=\"token punctuation\">,</span> Error<span class=\"token operator\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  mediaRecorder<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"dataavailable\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    chunks<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  mediaRecorder<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"stop\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    deferredBlob<span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">Blob</span><span class=\"token punctuation\">(</span>chunks<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">\"audio/ogg; codecs=opus\"</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  mediaRecorder<span class=\"token punctuation\">.</span><span class=\"token function\">start</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    mediaRecorder<span class=\"token punctuation\">.</span><span class=\"token function\">stop</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> deferredBlob<span class=\"token punctuation\">.</span>promise<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>By using our <code>Deferred</code> object, we can return a promise in one function, and resolve it in an event callback in a totally different place.</p> <h2 id=\"a-timeout-on-a-database-query\" tabindex=\"-1\">A timeout on a database query</h2> <p>Wanna add a timeout to your database queries, but your library doesn't offer that feature? Use deferred to roll your own:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">runQuery</span><span class=\"token punctuation\">(</span>query<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> timeout<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">const</span> deferred <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Deferred</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">const</span> isDone <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>timeout<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>isDone<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">      deferred<span class=\"token punctuation\">.</span><span class=\"token function\">reject</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">TimeoutError</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> timeout<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  dbConnection<span class=\"token punctuation\">.</span><span class=\"token function\">run</span><span class=\"token punctuation\">(</span>query<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    isDone <span class=\"token operator\">=</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    deferred<span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">catch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    deferred<span class=\"token punctuation\">.</span><span class=\"token function\">reject</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> deferred<span class=\"token punctuation\">.</span>promise<span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token function\">trackMetrics</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> data<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>Essentially, our deferred promise is wrapping the <code>dbConneciton.run</code> promise, so that we can have more control over the resolution of the promise that this function returns. Sure, you could wrap all of this into a <code>Promise</code> callback, but I find this a little easier to reason about.</p> <p>Have other good examples of <code>deferred</code> or <code>withResolvers</code>? Let me know about them!</p> ",
      "content_text": "I recently made a video about the deferred promise pattern in JavaScript. If you aren't familiar, the code is pretty simple: class Deferred&lt;T, E = unknown> {   promise: Promise&lt;T>;   resolve: (value: T | PromiseLike&lt;T>) => void = () => null;   reject: (reason?: E) => void = () => null;    constructor() {     this.promise = new Promise((resolve, reject) => {       this.resolve = resolve;       this.reject = reject;     });   } } I think of this as a kind of &quot;inverted promise&quot;, where you can access the resolve and reject functions from outside the promise callback. This is a useful enough pattern that it will soon be part of the Promise API! Alexander Cerutti pointed me to a TC39 Proposal for Promise.withResolvers that has made it to stage 3. Using that signature, we could rewrite the above code like this: function withResolvers&lt;T>() {   let resolve: (value: T | PromiseLike&lt;T>) => void = () => null;   let reject: (reason?: unknown) => void = () => null;    const promise = new Promise&lt;T>((_resolve, _reject) => {     resolve = _resolve;     reject = _reject;   });    return { resolve, reject, promise }; }; Same rose, another name. So, where is this pattern useful? Here are a few examples that I've run into before. Event-based APIs A lot of the web APIs or Node APIs are event-based, which can mean a typical pattern of doing everything inside a Promise callback just isn't ergonomic. Using the deferred pattern can keep your code clean and functional: In this example, I'm using the Web audio APIs to record (via MediaRecorder) audio from a MediaStream and into a Blob: function recordStreamAsBlob(stream: MediaStream): () => Promise&lt;Blob> {   const mediaRecorder = new MediaRecorder(stream);    const chunks: Array&lt;BlobPart> = [];   const deferredBlob = new Deferred&lt;Blob, Error>();    mediaRecorder.addEventListener(\"dataavailable\", (e) => {     chunks.push(e.data);   });    mediaRecorder.addEventListener(\"stop\", () => {     deferredBlob.resolve(new Blob(chunks, { type: \"audio/ogg; codecs=opus\" }));   });    mediaRecorder.start();    return () => {     mediaRecorder.stop();     return deferredBlob.promise;   }; } By using our Deferred object, we can return a promise in one function, and resolve it in an event callback in a totally different place. A timeout on a database query Wanna add a timeout to your database queries, but your library doesn't offer that feature? Use deferred to roll your own: function runQuery(query: string, timeout?: number) {   const deferred = new Deferred();   const isDone = false;    if (timeout) {     setTimeout(() => {       if (isDone) return;       deferred.reject(new TimeoutError());     }, timeout);   }    dbConnection.run(query).then((result) => {     isDone = true;     deferred.resolve(result);   }).catch((err) => {     deferred.reject(err);   });    return deferred.promise.then((data) => {     trackMetrics();     return data;   }); } Essentially, our deferred promise is wrapping the dbConneciton.run promise, so that we can have more control over the resolution of the promise that this function returns. Sure, you could wrap all of this into a Promise callback, but I find this a little easier to reason about. Have other good examples of deferred or withResolvers? Let me know about them! ",
      "date_published": "2023-08-01T00:00:00.000Z",
      "tags": [
        "javascript",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/dash-2023/",
      "url": "https://shaky.sh/dash-2023/",
      "title": "DASH 2023 in Review",
      "content_html": "<p>This week I was at <a href=\"https://www.dashcon.io/\">DASH 2023</a> and attended a bunch of cool sessions.</p> <ol> <li> <p><strong>AWS GameDay - Serverless work with Automation and Workflows</strong>: Hands-on session, where we got into a sandbox environment and solved actual problems with DataDog. I haven't used serverless much yet, but cool to see just how much visiblity you can have into your functions.</p> </li> <li> <p><strong>Diagnose and Optimize CPU Performance with Continuous Profiler</strong>: Profiling is great when developing locally, but it becomes even more powerful when you can capture traces of what's happening in production.</p> </li> <li> <p><strong>DASH Keynote</strong>: DataDog is releasing a ton of new products. There are several Generative-AI-related tools, but I'm probably most interested in some offerings for finding and managing code-level vulnerabilities and static analysis.</p> </li> <li> <p><strong>The Darkside of GraphQL</strong>: GraphQL is powerful, but can be challenging to productionize. Make sure you're using it securely!</p> </li> <li> <p><strong>From Solution to Startup</strong>: Stories of products that began inside other companies.</p> </li> <li> <p><strong>The Beauty of a CLI and how we scaled our Operations Software Need</strong>: A delightful talk about begin inspired by classic CLI tools (like <code>cp</code>) and building internal tools that do one thing well.</p> </li> <li> <p><strong>The Edge of Observability: How Chick-fil-A Observes a fleet of 2800 Restaurant-deployed K8s Clusters</strong>: Grills, fryers, and fridges as IOT devices, with a K3s cluster on a few Intel NUCs in every location. This was a fascinating look at using a lot of the observabilty tools we're familiar with in a very different environment.</p> </li> </ol> <p>Pretty sure a bunch of these talks were recorded; if those recording appear on YouTube, I'll add links above.</p> ",
      "content_text": "This week I was at DASH 2023 and attended a bunch of cool sessions.   AWS GameDay - Serverless work with Automation and Workflows: Hands-on session, where we got into a sandbox environment and solved actual problems with DataDog. I haven't used serverless much yet, but cool to see just how much visiblity you can have into your functions.   Diagnose and Optimize CPU Performance with Continuous Profiler: Profiling is great when developing locally, but it becomes even more powerful when you can capture traces of what's happening in production.   DASH Keynote: DataDog is releasing a ton of new products. There are several Generative-AI-related tools, but I'm probably most interested in some offerings for finding and managing code-level vulnerabilities and static analysis.   The Darkside of GraphQL: GraphQL is powerful, but can be challenging to productionize. Make sure you're using it securely!   From Solution to Startup: Stories of products that began inside other companies.   The Beauty of a CLI and how we scaled our Operations Software Need: A delightful talk about begin inspired by classic CLI tools (like cp) and building internal tools that do one thing well.   The Edge of Observability: How Chick-fil-A Observes a fleet of 2800 Restaurant-deployed K8s Clusters: Grills, fryers, and fridges as IOT devices, with a K3s cluster on a few Intel NUCs in every location. This was a fascinating look at using a lot of the observabilty tools we're familiar with in a very different environment.   Pretty sure a bunch of these talks were recorded; if those recording appear on YouTube, I'll add links above. ",
      "date_published": "2023-08-02T00:00:00.000Z",
      "tags": [
        "eng",
        "conferences"
      ]
    },
    {
      "id": "https://shaky.sh/css-text-decoration-and-headings/",
      "url": "https://shaky.sh/css-text-decoration-and-headings/",
      "title": "CSS text-decoration and headings",
      "content_html": "<p>I'm no designer, but I've been having fun tweaking the styling for this site recently. One fun bit has been the <code>&lt;h2&gt;</code> elements I use as headings with a post. Like this:</p> <h2 id=\"hey-there\" tabindex=\"-1\">Hey there</h2> <p>The fun bit, of course, is the underlining. You might think it's a simple <code>border-bottom</code>. <em>Au contraire</em>! A <code>border-bottom</code> can't skip over glyph descenders (the &quot;tail&quot; on the <code>y</code> in the heading above).</p> <p>Instead, I'm using <code>text-decoration</code>, which you typically see on links/anchors, and which does skip over glyph descenders<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">1</a></sup>.</p> <pre class=\"language-css\"><code class=\"language-css\"><span class=\"highlight-line\"><span class=\"token selector\">.prose h2</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token property\">text-decoration</span><span class=\"token punctuation\">:</span> underline<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token property\">text-decoration-color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--primary-accent-color<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <h2 id=\"whyyyyyyyy%3F\" tabindex=\"-1\">Whyyyyyyyy?</h2> <p>Because it's a fun look! As mentioned, I'm no designer.</p> <p>But I don't want headings to be mistaken for links. So I wanted this line to continue the full width of the heading. The only way (I could find) to do this is by adding non-breaking spaces after the text in the heading. The simplest way to do that is with <code>:after</code> content:</p> <pre class=\"language-css\"><code class=\"language-css\"><span class=\"highlight-line\"><span class=\"token selector\">.prose h2:after</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token property\">content</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\" \\a0\\a0\\a0\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>This is three non-breaking spaces, but actually, I'm adding a lot of them enought to fill out the rest of the line even when my text is short. Too many for most cases, actually. So now we have to hide the overflow:</p> <pre class=\"language-css\"><code class=\"language-css\"><span class=\"highlight-line\"><span class=\"token selector\">.prose h2</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token property\">white-space</span><span class=\"token punctuation\">:</span> nowrap<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token property\">overflow</span><span class=\"token punctuation\">:</span> hidden<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>This means, of course, that I can never write a heading that may break onto multiple lines. Pretty sure I can live with that for now.</p> <p>In case this changes in the future, here's an image of what this looks like today.</p> <p><img width=\"704\" alt=\"Two level-two headings. The first says 'Hey there', the second says `Why' with eight 'y's. They demonstrate the styling of the level-two headings in this post, in dark mode, at the time of this writing\" src=\"https://cdn.some.pics/shaky/64cf0cc681dc1.jpg\" fetchpriority=\"low\" loading=\"lazy\"></p> <p>If there's a better way to do this, I'd love to hear! If this looks bad in your browser, please send me a screenshot!</p> <hr class=\"footnotes-sep\"><section class=\"footnotes\"><ol class=\"footnotes-list\"><li id=\"fn1\" class=\"footnote-item\"><p>As I recently learned, you can control that with <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-skip-ink\"><code>text-decoration-skip-ink</code></a>. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p> </li> </ol> </section> ",
      "content_text": "I'm no designer, but I've been having fun tweaking the styling for this site recently. One fun bit has been the &lt;h2&gt; elements I use as headings with a post. Like this: Hey there The fun bit, of course, is the underlining. You might think it's a simple border-bottom. Au contraire! A border-bottom can't skip over glyph descenders (the &quot;tail&quot; on the y in the heading above). Instead, I'm using text-decoration, which you typically see on links/anchors, and which does skip over glyph descenders1. .prose h2 {   text-decoration: underline;   text-decoration-color: var(--primary-accent-color); } Whyyyyyyyy? Because it's a fun look! As mentioned, I'm no designer. But I don't want headings to be mistaken for links. So I wanted this line to continue the full width of the heading. The only way (I could find) to do this is by adding non-breaking spaces after the text in the heading. The simplest way to do that is with :after content: .prose h2:after {   content: \" \\a0\\a0\\a0\"; } This is three non-breaking spaces, but actually, I'm adding a lot of them enought to fill out the rest of the line even when my text is short. Too many for most cases, actually. So now we have to hide the overflow: .prose h2 {   white-space: nowrap;   overflow: hidden; } This means, of course, that I can never write a heading that may break onto multiple lines. Pretty sure I can live with that for now. In case this changes in the future, here's an image of what this looks like today.  If there's a better way to do this, I'd love to hear! If this looks bad in your browser, please send me a screenshot! As I recently learned, you can control that with text-decoration-skip-ink. ↩︎    ",
      "date_published": "2023-08-04T00:00:00.000Z",
      "tags": [
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/bram/",
      "url": "https://shaky.sh/bram/",
      "title": "To Bram",
      "content_html": "<p>Bram Moolenaar is the reason I'm using Vim today. And not just because he built it.</p> <p>I remember clearly when I decided to make Vim my daily editor. It was early summer of 2010, and I was finishing my first year of university. On that particular day, I was babysitting my seven-year-old cousin<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">1</a></sup>, and while he was preoccupied, I watched a <a href=\"https://www.youtube.com/watch?v=eX9m3g5J-XA\">Google Tech Talk</a><sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">2</a></sup> by <a href=\"https://www.moolenaar.net/\">Bram Moolenaar</a>, the maintainer and <a href=\"https://en.wikipedia.org/wiki/Benevolent_dictator_for_life\">benevolent dictator for life</a> of <a href=\"https://www.vim.org/\">Vim</a><sup class=\"footnote-ref\"><a href=\"#fn3\" id=\"fnref3\">3</a></sup>.</p> <p>I'd started programming a few years earlier, so I was already aware for Vi &amp; Vim (I knew how to exit, at least). But as Bram talked through 7 habits for highly effective text editing, I decided to give this extraordinarily different editor a shot.</p> <p>Just over 13 years later, I'm still using it daily.</p> <p>Of course, over the years, I've tried other editors as well. For a short time, I tried Sublime Text. When GitHub released Atom, I tried that as well. I used IntelliJ IDEA (with the Vim extension) for probably a year. I've made various attempts to use VS Code (both with and without the Vim extension) over the years as well. I think I even tried TextMate 2 at one point.</p> <p>In every instance, I've always returned to Vim (or, <a href=\"https://neovim.io/\">Neovim</a> now). Its speed, flexibility, and portability are unmatched, at least for me.</p> <p>I was sad to see <a href=\"https://groups.google.com/g/vim_announce/c/tWahca9zkt4\">the news of Bram's passing</a>. My condolences go out to his family, who no doubt feel this loss much more than those of us who were simply fans of an amazing developer and beneficiaries of his work.</p> <p>To leave Vim as a legacy (at least, a legacy to those of us who didn't know him personally) is no small thing. From memes and rants to book and tutorials, I can't think of another piece of software that more people feel so strongly about.</p> <hr class=\"footnotes-sep\"><section class=\"footnotes\"><ol class=\"footnotes-list\"><li id=\"fn1\" class=\"footnote-item\"><p>Shoutout to Joseph, he's now half-way through a CS degree himself. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p> </li> <li id=\"fn2\" class=\"footnote-item\"><p>If memory serves, I watched this talk on Google Video originally. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p> </li> <li id=\"fn3\" class=\"footnote-item\"><p><a href=\"https://www.vim.org/\">Vim.org</a> is one of the very few websites I know of that still uses <code>&lt;table&gt;</code> for layout. Knowing that little piece of web history still lives on somewhere is very pleasing. <a href=\"#fnref3\" class=\"footnote-backref\">↩︎</a></p> </li> </ol> </section> ",
      "content_text": "Bram Moolenaar is the reason I'm using Vim today. And not just because he built it. I remember clearly when I decided to make Vim my daily editor. It was early summer of 2010, and I was finishing my first year of university. On that particular day, I was babysitting my seven-year-old cousin1, and while he was preoccupied, I watched a Google Tech Talk2 by Bram Moolenaar, the maintainer and benevolent dictator for life of Vim3. I'd started programming a few years earlier, so I was already aware for Vi &amp; Vim (I knew how to exit, at least). But as Bram talked through 7 habits for highly effective text editing, I decided to give this extraordinarily different editor a shot. Just over 13 years later, I'm still using it daily. Of course, over the years, I've tried other editors as well. For a short time, I tried Sublime Text. When GitHub released Atom, I tried that as well. I used IntelliJ IDEA (with the Vim extension) for probably a year. I've made various attempts to use VS Code (both with and without the Vim extension) over the years as well. I think I even tried TextMate 2 at one point. In every instance, I've always returned to Vim (or, Neovim now). Its speed, flexibility, and portability are unmatched, at least for me. I was sad to see the news of Bram's passing. My condolences go out to his family, who no doubt feel this loss much more than those of us who were simply fans of an amazing developer and beneficiaries of his work. To leave Vim as a legacy (at least, a legacy to those of us who didn't know him personally) is no small thing. From memes and rants to book and tutorials, I can't think of another piece of software that more people feel so strongly about. Shoutout to Joseph, he's now half-way through a CS degree himself. ↩︎  If memory serves, I watched this talk on Google Video originally. ↩︎  Vim.org is one of the very few websites I know of that still uses &lt;table&gt; for layout. Knowing that little piece of web history still lives on somewhere is very pleasing. ↩︎    ",
      "date_published": "2023-08-06T00:00:00.000Z",
      "tags": [
        "eng",
        "tech"
      ]
    },
    {
      "id": "https://shaky.sh/links/heather-buchel-normal-web-things/",
      "url": "https://shaky.sh/links/heather-buchel-normal-web-things/",
      "title": "Just normal web things",
      "content_html": "<p>This is exactly how I've been feeling recently. In an industry of web apps that are trying to be native apps, I've been trying to lean into the inherent strengths of the web, instead of removing them and then trying to compete at a disadvantage with native apps.</p> <p>Related: <a href=\"https://www.youtube.com/watch?v=NBFlyG60ar4\">Francisco Tolmasky: The Browser Isn't Feature Complete</a></p> ",
      "content_text": "This is exactly how I've been feeling recently. In an industry of web apps that are trying to be native apps, I've been trying to lean into the inherent strengths of the web, instead of removing them and then trying to compete at a disadvantage with native apps. Related: Francisco Tolmasky: The Browser Isn't Feature Complete ",
      "date_published": "2023-08-09T00:00:00.000Z"
    },
    {
      "id": "https://shaky.sh/ts-covariance-contravariance/",
      "url": "https://shaky.sh/ts-covariance-contravariance/",
      "title": "TypeScript Covariance and Contravariance",
      "content_html": "<p>I'll admit: this is a pretty intensely nerdy corner of TypeScript, and one that I haven't yet found a use for in a production system. Here's hoping that one day I run into a contravariance problem and know exactly what to do because I stumbled across this bit of syntax I formerly knew nothing about.</p> <p>(I've made a <a href=\"https://youtu.be/bWF0KrhDuuE\">video about this topic</a> if watching is more your thing.)</p> <h2 id=\"a-bit-of-set-theory\" tabindex=\"-1\">A bit of set theory</h2> <p>TypeScript is structurally-typed, which means that for a value to be <strong>of a type</strong>, it only needs to fulfil the requirements of that type. It doesn't need to be created with a particular constructor, as is the case with many strongly-typed languages.</p> <p>An example: this <code>jobName</code> variable can be treated as all of the following types:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">const</span> jobName <span class=\"token operator\">=</span> <span class=\"token string\">\"send-email\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">JobName1</span> <span class=\"token operator\">=</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">JobName2</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"send-email\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"fulfil-order\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"publish-report\"</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">JobName3</span> <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token builtin\">string</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">-email</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">JobName4</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"send-email\"</span><span class=\"token punctuation\">;</span></span></code></pre> <p>These types get narrower as we go down, with <code>string</code> being the broadest, and <code>&quot;send-email&quot;</code> being the most narrow (only matching a single value).</p> <p><img src=\"https://shaky.sh/assets/2023-08-11-1-string-set-theory.png\" alt=\"\"></p> <p>Of course, in set theory these are called subsets: <em>a union of string literals is a subset of all string values</em>. In programing languages, we usually call these <strong>subtypes</strong>. For many languages, subtypes are only create via inheritance, but because of the shape-based nature of TypeScript, we don't need the explicit relationship between these types.</p> <p>With this understanding, we can take a look at <strong>covariance</strong> and <strong>contravariance</strong>.</p> <h2 id=\"co-what-now%3F\" tabindex=\"-1\">co-what-now?</h2> <p><em>Covariance</em> and <em>contravariance</em> describe how subtype relationship operate <strong>inside types with type arguments</strong>; that is inside <strong>generics</strong>.</p> <p>Let's say we have these two types in our job queuing system, as well as a function for executing jobs.</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Job</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  queueName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  enqueuedAt<span class=\"token operator\">:</span> Date<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  transactionId<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  name<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">PriorityJob</span> <span class=\"token operator\">=</span> Job <span class=\"token operator\">&amp;</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  priority<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></span> <span class=\"highlight-line\">  level<span class=\"token operator\">:</span> <span class=\"token number\">1</span> <span class=\"token operator\">|</span> <span class=\"token number\">2</span> <span class=\"token operator\">|</span> <span class=\"token number\">3</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">executeJob</span><span class=\"token punctuation\">(</span>job<span class=\"token operator\">:</span> Job<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token comment\">// ...</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span></code></pre> <p>This function will accept both <code>Job</code> objects and <code>PriorityJob</code> objects, because <code>PriorityJob</code> is sub-type of <code>Job</code>. So far, so normal.</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">function</span> <span class=\"token function\">executeJob</span><span class=\"token punctuation\">(</span>job<span class=\"token operator\">:</span> Job<span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">const</span> j1<span class=\"token operator\">:</span> Job<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">const</span> j2<span class=\"token operator\">:</span> PriorityJob<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token function\">executeJob</span><span class=\"token punctuation\">(</span>j1<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token function\">executeJob</span><span class=\"token punctuation\">(</span>j2<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>But what about a function that takes an array of jobs?</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">executeJobs</span><span class=\"token punctuation\">(</span>job<span class=\"token operator\">:</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span>Job<span class=\"token operator\">></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token comment\">// ...</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Will this function accept an <code>Array&lt;PriorityJob&gt;</code> argument? It will!</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">function</span> <span class=\"token function\">executeJobs</span><span class=\"token punctuation\">(</span>jobs<span class=\"token operator\">:</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span>Job<span class=\"token operator\">></span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">const</span> j3<span class=\"token operator\">:</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span>Job<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">const</span> j4<span class=\"token operator\">:</span> <span class=\"token builtin\">Array</span><span class=\"token operator\">&lt;</span>PriorityJob<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token function\">executeJobs</span><span class=\"token punctuation\">(</span>j3<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token function\">executeJobs</span><span class=\"token punctuation\">(</span>j4<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>More generally, if <code>B</code> extends/intersects/is-a-subtype-of <code>A</code>, then <code>Array&lt;B&gt;</code> also extends/intersects/is-a-subtype-of <code>Array&lt;A&gt;</code>. That's covariance: <code>Array</code> is considered <strong>covariant</strong> on <code>T</code>.</p> <p>Covariance is the behaviour you get on most generic types, and certainly on most of the built-in generics: <code>Promise</code>, <code>Omit</code>, <code>ReadonlyArray</code>, <code>Map</code>, and so on. Any custom wrapper or envelope type with a generic argument <code>T</code> will likely be covariant over <code>T</code>.</p> <h2 id=\"contravariance\" tabindex=\"-1\">Contravariance</h2> <p>But what if our job queue system wants to use custom job executor functions? The type might look something like this:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Executor<span class=\"token operator\">&lt;</span><span class=\"token constant\">J</span><span class=\"token operator\">></span></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>j<span class=\"token operator\">:</span> <span class=\"token constant\">J</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token string\">'success'</span> <span class=\"token operator\">|</span> <span class=\"token string\">'failure'</span><span class=\"token punctuation\">;</span></span></code></pre> <p>If we create an <code>registerExecutor</code> function that takes an <code>Executor&lt;Job&gt;</code>, does covariance still hold? Let's find out:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">function</span> <span class=\"token function\">registerExecutor</span><span class=\"token punctuation\">(</span>e<span class=\"token operator\">:</span> Executor<span class=\"token operator\">&lt;</span>Job<span class=\"token operator\">></span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">const</span> e1<span class=\"token operator\">:</span> Executor<span class=\"token operator\">&lt;</span>Job<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">const</span> e2<span class=\"token operator\">:</span> Executor<span class=\"token operator\">&lt;</span>PriorityJob<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token function\">registerExecutor</span><span class=\"token punctuation\">(</span>e1<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token function\">registerExecutor</span><span class=\"token punctuation\">(</span>e2<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// error!</span></span></code></pre> <p>It doesn't work! <code>Executor&lt;PrimaryJob&gt;</code> doesn't meet the requirements of <code>Executor&lt;Job&gt;</code>. Here's the error we get:</p> <pre class=\"language-text\"><code class=\"language-text\"><span class=\"highlight-line\">Argument of type 'PriorityJobExecutor' is not assignable to parameter of type 'Executor<Job>'.</Job></span> <span class=\"highlight-line\">  Types of parameters 'j' and 'j' are incompatible.</span> <span class=\"highlight-line\">    Type 'Job' is not assignable to type 'PriorityJob'.</span> <span class=\"highlight-line\">      Type 'Job' is missing the following properties from type '{ priority: true; level: 1 | 2 | 3; }': priority, level(2345)</span></code></pre> <p>What's happening is this: our <code>registerExecutor</code> function expects to receive a function that can take a <code>Job</code> as an argument. A function that takes a <code>PriorityJob</code> doesn't meet that requirement, because it expects to receive a <strong>narrower type</strong> than <code>Job</code>. If we're going to be passing <code>Job</code> instances to this function, is can't require something more specific (<code>PriorityJob</code>), right?</p> <p>What's interesting, though, is that the following works. Notice the signature of <code>registerPriorityExecutor</code>:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">function</span> <span class=\"token function\">registerPriorityExecutor</span><span class=\"token punctuation\">(</span>e<span class=\"token operator\">:</span> Executor<span class=\"token operator\">&lt;</span>PriorityJob<span class=\"token operator\">></span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">const</span> e1<span class=\"token operator\">:</span> Executor<span class=\"token operator\">&lt;</span>Job<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">declare</span> <span class=\"token keyword\">const</span> e2<span class=\"token operator\">:</span> Executor<span class=\"token operator\">&lt;</span>PriorityJob<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token function\">registerPriorityExecutor</span><span class=\"token punctuation\">(</span>e1<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token function\">registerPriorityExecutor</span><span class=\"token punctuation\">(</span>e2<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>If <code>registerPriorityExecutor</code> expects to receive a function that takes a <code>PriorityJob</code>, then it can also receive a function that takes a <code>Job</code>. How so? Well, every <code>PriorityJob</code> is also a <code>Job</code>, so a function that can process a <code>Job</code> can also process a <code>PriorityJob</code>.</p> <p>All this means that our <code>Executor</code> type is <strong>contravariant</strong> on <code>J</code>: it reverses the subtype order: <code>Executor&lt;Job&gt;</code> is now a subtype of <code>Executor&lt;PriorityJob&gt;</code>.</p> <h2 id=\"inputs-and-outputs\" tabindex=\"-1\">Inputs and Outputs</h2> <p>So all function types with a generic parameter are contravariant on that parameter? Not exactly. It depends on whether it's an argument or a return type that's generic: if it's an <em>input</em> or an <em>output</em>. The rule is this:</p> <ul> <li>Input types (that is, argument types) are covariant.</li> <li>Output types (that is, return types) are contravariant.</li> </ul> <p>Mostly, TypeScript infers this correctly, but if you want to be explicit, the <code>in</code> and <code>out</code> modifiers were <a href=\"https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#optional-variance-annotations-for-type-parameters\">introduced in v4.7</a> for exactly this.</p> <p>To demonstrate, let's say we have a queue for managing jobs:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Queue<span class=\"token operator\">&lt;</span><span class=\"token constant\">J</span><span class=\"token operator\">></span></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token function\">enqueue</span><span class=\"token punctuation\">(</span>j<span class=\"token operator\">:</span> <span class=\"token constant\">J</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token function\">getJob</span><span class=\"token punctuation\">(</span>id<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token constant\">J</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span></code></pre> <p>We want to use <code>J</code> as both an input and an output, so we can explicitly declare this with like so:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Queue<span class=\"token operator\">&lt;</span><span class=\"token keyword\">in</span> out <span class=\"token constant\">J</span><span class=\"token operator\">></span></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token function\">enqueue</span><span class=\"token punctuation\">(</span>j<span class=\"token operator\">:</span> <span class=\"token constant\">J</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token function\">getJob</span><span class=\"token punctuation\">(</span>id<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token constant\">J</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Play around with the various permutations of this to get familiar with it, but in this case, with both <code>in</code> and <code>out</code> modifiers declared, TypeScript will never accept a subtype or supertype of <code>J</code>. So, we'll never be able to assign a <code>Queue&lt;Job&gt;</code> to a <code>Queue&lt;PriorityJob&gt;</code>, or vice versa.</p> <h2 id=\"more-info\" tabindex=\"-1\">More Info</h2> <p>A few links that helped me wrap my head around this topic:</p> <ul> <li><a href=\"https://tsplay.dev/mqypYm\">TypeScript Playground with the above code</a></li> <li><a href=\"https://dmitripavlutin.com/typescript-covariance-contravariance/#2-covariance\">Covariance and Contravariance in TypeScript</a></li> <li><a href=\"https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)\">Wikipedia: Covariance and contravariance (computer science)</a></li> <li><a href=\"https://github.com/microsoft/TypeScript/pull/48240\">GitHub: microsoft/TypeScript: Optional variance annotations</a></li> </ul> ",
      "content_text": "I'll admit: this is a pretty intensely nerdy corner of TypeScript, and one that I haven't yet found a use for in a production system. Here's hoping that one day I run into a contravariance problem and know exactly what to do because I stumbled across this bit of syntax I formerly knew nothing about. (I've made a video about this topic if watching is more your thing.) A bit of set theory TypeScript is structurally-typed, which means that for a value to be of a type, it only needs to fulfil the requirements of that type. It doesn't need to be created with a particular constructor, as is the case with many strongly-typed languages. An example: this jobName variable can be treated as all of the following types: const jobName = \"send-email\";  type JobName1 = string; type JobName2 = \"send-email\" | \"fulfil-order\" | \"publish-report\"; type JobName3 = `${string}-email`; type JobName4 = \"send-email\"; These types get narrower as we go down, with string being the broadest, and &quot;send-email&quot; being the most narrow (only matching a single value).  Of course, in set theory these are called subsets: a union of string literals is a subset of all string values. In programing languages, we usually call these subtypes. For many languages, subtypes are only create via inheritance, but because of the shape-based nature of TypeScript, we don't need the explicit relationship between these types. With this understanding, we can take a look at covariance and contravariance. co-what-now? Covariance and contravariance describe how subtype relationship operate inside types with type arguments; that is inside generics. Let's say we have these two types in our job queuing system, as well as a function for executing jobs. type Job = {   queueName: string;   enqueuedAt: Date;   transactionId: string;   name: string; };  type PriorityJob = Job &amp; {   priority: true,   level: 1 | 2 | 3 };  function executeJob(job: Job) {   // ... }; This function will accept both Job objects and PriorityJob objects, because PriorityJob is sub-type of Job. So far, so normal. declare function executeJob(job: Job): void; declare const j1: Job; declare const j2: PriorityJob;  executeJob(j1); executeJob(j2); But what about a function that takes an array of jobs? function executeJobs(job: Array&lt;Job>) {   // ... }; Will this function accept an Array&lt;PriorityJob&gt; argument? It will! declare function executeJobs(jobs: Array&lt;Job>): void; declare const j3: Array&lt;Job>; declare const j4: Array&lt;PriorityJob>;  executeJobs(j3); executeJobs(j4); More generally, if B extends/intersects/is-a-subtype-of A, then Array&lt;B&gt; also extends/intersects/is-a-subtype-of Array&lt;A&gt;. That's covariance: Array is considered covariant on T. Covariance is the behaviour you get on most generic types, and certainly on most of the built-in generics: Promise, Omit, ReadonlyArray, Map, and so on. Any custom wrapper or envelope type with a generic argument T will likely be covariant over T. Contravariance But what if our job queue system wants to use custom job executor functions? The type might look something like this: type Executor&lt;J> = (j: J) => 'success' | 'failure'; If we create an registerExecutor function that takes an Executor&lt;Job&gt;, does covariance still hold? Let's find out: declare function registerExecutor(e: Executor&lt;Job>): void; declare const e1: Executor&lt;Job>; declare const e2: Executor&lt;PriorityJob>;  registerExecutor(e1); registerExecutor(e2); // error! It doesn't work! Executor&lt;PrimaryJob&gt; doesn't meet the requirements of Executor&lt;Job&gt;. Here's the error we get: Argument of type 'PriorityJobExecutor' is not assignable to parameter of type 'Executor'.   Types of parameters 'j' and 'j' are incompatible.     Type 'Job' is not assignable to type 'PriorityJob'.       Type 'Job' is missing the following properties from type '{ priority: true; level: 1 | 2 | 3; }': priority, level(2345) What's happening is this: our registerExecutor function expects to receive a function that can take a Job as an argument. A function that takes a PriorityJob doesn't meet that requirement, because it expects to receive a narrower type than Job. If we're going to be passing Job instances to this function, is can't require something more specific (PriorityJob), right? What's interesting, though, is that the following works. Notice the signature of registerPriorityExecutor: declare function registerPriorityExecutor(e: Executor&lt;PriorityJob>): void; declare const e1: Executor&lt;Job>; declare const e2: Executor&lt;PriorityJob>;  registerPriorityExecutor(e1); registerPriorityExecutor(e2); If registerPriorityExecutor expects to receive a function that takes a PriorityJob, then it can also receive a function that takes a Job. How so? Well, every PriorityJob is also a Job, so a function that can process a Job can also process a PriorityJob. All this means that our Executor type is contravariant on J: it reverses the subtype order: Executor&lt;Job&gt; is now a subtype of Executor&lt;PriorityJob&gt;. Inputs and Outputs So all function types with a generic parameter are contravariant on that parameter? Not exactly. It depends on whether it's an argument or a return type that's generic: if it's an input or an output. The rule is this:  Input types (that is, argument types) are covariant. Output types (that is, return types) are contravariant.  Mostly, TypeScript infers this correctly, but if you want to be explicit, the in and out modifiers were introduced in v4.7 for exactly this. To demonstrate, let's say we have a queue for managing jobs: type Queue&lt;J> = {   enqueue(j: J): void;   getJob(id: string): J; }; We want to use J as both an input and an output, so we can explicitly declare this with like so: type Queue&lt;in out J> = {   enqueue(j: J): void;   getJob(id: string): J; }; Play around with the various permutations of this to get familiar with it, but in this case, with both in and out modifiers declared, TypeScript will never accept a subtype or supertype of J. So, we'll never be able to assign a Queue&lt;Job&gt; to a Queue&lt;PriorityJob&gt;, or vice versa. More Info A few links that helped me wrap my head around this topic:  TypeScript Playground with the above code Covariance and Contravariance in TypeScript Wikipedia: Covariance and contravariance (computer science) GitHub: microsoft/TypeScript: Optional variance annotations  ",
      "date_published": "2023-08-11T00:00:00.000Z",
      "tags": [
        "typescript",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/more-ts-contravariance-never/",
      "url": "https://shaky.sh/more-ts-contravariance-never/",
      "title": "Contravariance? Never!",
      "content_html": "<p>Yesterday some colleagues and I were discussing the relationship between <code>any</code>, <code>unknown</code>, and <code>never</code> in TypeScript. The mental model that's been helpful for me is Set Theory:</p> <ul> <li><code>unknown</code> is the set of all possible values. <ul> <li>If a function takes an <code>unknown</code> argument, you can pass it any value.</li> </ul> </li> <li><code>never</code> is the empty set. <ul> <li>If a function takes a <code>never</code> argument, there's no value you can pass it.<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">1</a></sup></li> </ul> </li> <li><code>any</code> does not conform to set theory. <ul> <li>It's the equivalent of the compiler throwing up its hands and saying &quot;okay, fine, you drive!&quot;</li> </ul> </li> </ul> <h2 id=\"an-example\" tabindex=\"-1\">An Example</h2> <p>The catalysts of our converstaion were the <code>Parameters</code> and <code>ReturnType</code> utility types built into TypeScript. If you aren't familiar, here they are as defined in <a href=\"https://github.com/microsoft/TypeScript/blob/877d9d3/src/lib/es5.d.ts#L1615\">es5.d.ts in the TypeScript source</a></p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Parameters<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span></span> <span class=\"token builtin\">any</span><span class=\"token operator\">></span> <span class=\"token operator\">=</span> <span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token keyword\">infer</span> <span class=\"token constant\">P</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token builtin\">any</span> <span class=\"token operator\">?</span> <span class=\"token constant\">P</span> <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">ReturnType<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span></span> <span class=\"token builtin\">any</span><span class=\"token operator\">></span> <span class=\"token operator\">=</span> <span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">infer</span> <span class=\"token constant\">R</span> <span class=\"token operator\">?</span> <span class=\"token constant\">R</span> <span class=\"token operator\">:</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">;</span></span></code></pre> <p>The <code>unknown</code> type was <a href=\"https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type\">introduced in TS 3.0</a> as a type-safe version of <code>any</code>, so it seemed weird to me that these core utility types are still using <code>any</code> when there are better options. Can't we just replace <code>any</code> with <code>unknonwn</code> in <code>Parameters</code> and <code>ReturnTypes</code> and move on?</p> <p>Actually, no. Try it, and you'll see that something is wrong:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">ParametersNoAny<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token builtin\">unknown</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span></span> <span class=\"token builtin\">unknown</span><span class=\"token operator\">></span> <span class=\"token operator\">=</span> <span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token keyword\">infer</span> <span class=\"token constant\">P</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token builtin\">unknown</span> <span class=\"token operator\">?</span> <span class=\"token constant\">P</span> <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">ReturnTypeNoAny<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token builtin\">unknown</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span></span> <span class=\"token builtin\">unknown</span><span class=\"token operator\">></span> <span class=\"token operator\">=</span> <span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token builtin\">unknown</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">infer</span> <span class=\"token constant\">R</span> <span class=\"token operator\">?</span> <span class=\"token constant\">R</span> <span class=\"token operator\">:</span> <span class=\"token builtin\">unknown</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token function\">testFn</span><span class=\"token punctuation\">(</span>a1<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> a2<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> <span class=\"token function\">parseInt</span><span class=\"token punctuation\">(</span>a1<span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">===</span> a2<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Args</span> <span class=\"token operator\">=</span> ParametersNoAny<span class=\"token operator\">&lt;</span><span class=\"token keyword\">typeof</span> testFn<span class=\"token operator\">></span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// error!</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Ret</span> <span class=\"token operator\">=</span> ReturnTypeNoAny<span class=\"token operator\">&lt;</span><span class=\"token keyword\">typeof</span> testFn<span class=\"token operator\">></span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// error!</span></span></code></pre> <p>When we try to pass <code>typeof testFn</code> to either of our new utilities, we get this type error:</p> <pre class=\"language-text\"><code class=\"language-text\"><span class=\"highlight-line\">Type '(a1: string, a2: number) => boolean' does not satisfy the constraint '(...args: unknown[]) => unknown'.</span> <span class=\"highlight-line\">  Types of parameters 'a1' and 'args' are incompatible.</span> <span class=\"highlight-line\">    Type 'unknown' is not assignable to type 'string'.</span></code></pre> <p>When I first saw this error, it seemed backwards to me. I don't want to assign <code>unknown</code> to <code>string</code>, I want to go the other way, right? I'm passing my string-arged function <em>into</em> these utilities, so I'm trying to assign <code>string</code> where the constraint is <code>unknown</code>, which should accept everything, right? Right?!?</p> <p>Actually, this is a situation where it's helpful to understand contravariance. I wrote a post about <a href=\"https://shaky.sh/ts-covariance-contravariance/\">covariance and contravariance in TypeScript</a> last year, but I still don't feel like I have a really good grasp of when it's relevant or even in play. But let's make an attempt, using the real-world example of packing boxes.</p> <h2 id=\"what-kind-of-box-do-you-want%3F\" tabindex=\"-1\">What kind of box do you want?</h2> <p>Let's think of <code>ParametersNoAny</code> and <code>ReturnTypeNoAny</code> as you when helping a friend move, and generic argument as the boxes you pack their stuff into.</p> <p>The constraint on the generic parameter (<code>T extends ...</code>) is a request for a box that fits a specific item. And right now, that item is <code>unknown[]</code>: in other words, you want a box that can fit any number of any items. In our terms, that's the set of all possible sets of arguments. There are no functions<sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">2</a></sup> in the set of &quot;functions that accept all possible sets of arguments&quot;! No wonder we get an error when we pass in a function that only accepts a string and a number.</p> <p>The solution here is to say that these functions should take <code>never[]</code> arguments:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">ParametersNoAny<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span></span> <span class=\"token builtin\">unknown</span><span class=\"token operator\">></span> <span class=\"token operator\">=</span> <span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token keyword\">infer</span> <span class=\"token constant\">P</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token builtin\">unknown</span> <span class=\"token operator\">?</span> <span class=\"token constant\">P</span> <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">ReturnTypeNoAny<span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span></span> <span class=\"token builtin\">unknown</span><span class=\"token operator\">></span> <span class=\"token operator\">=</span> <span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">infer</span> <span class=\"token constant\">R</span> <span class=\"token operator\">?</span> <span class=\"token constant\">R</span> <span class=\"token operator\">:</span> <span class=\"token builtin\">unknown</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Now, we are asking for a box that <em>can fit no items</em>. Not a box that <em>must</em> fit no items, but a box that <em>can</em>. To put it another way, you want a box that doesn't need to work for a specific item or set of items: any box will do. Your friend can pass you a box that fits a toaster, or a screwdriver, or a set of tires, and you'll be happy with whatever it is.</p> <h2 id=\"it-works!\" tabindex=\"-1\">It works!</h2> <p>With these changes, our utility types now work! No errors, and they correctly infer the types we want.</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Args</span> <span class=\"token operator\">=</span> ParametersNoAny<span class=\"token operator\">&lt;</span><span class=\"token keyword\">typeof</span> testFn<span class=\"token operator\">></span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// [a1: string, a2: number]</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Ret</span> <span class=\"token operator\">=</span> ReturnTypeNoAny<span class=\"token operator\">&lt;</span><span class=\"token keyword\">typeof</span> testFn<span class=\"token operator\">></span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// boolean</span></span></code></pre> <p>So glad I finally understand contravariance ... for this week.</p> <hr class=\"footnotes-sep\"><section class=\"footnotes\"><ol class=\"footnotes-list\"><li id=\"fn1\" class=\"footnote-item\"><p>and yet you <strong>must</strong> pass it a variable. But that's a different post. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p> </li> <li id=\"fn2\" class=\"footnote-item\"><p>expect functions that take <code>(...args: unknown[])</code>, I guess. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p> </li> </ol> </section> ",
      "content_text": "Yesterday some colleagues and I were discussing the relationship between any, unknown, and never in TypeScript. The mental model that's been helpful for me is Set Theory:  unknown is the set of all possible values.  If a function takes an unknown argument, you can pass it any value.   never is the empty set.  If a function takes a never argument, there's no value you can pass it.1   any does not conform to set theory.  It's the equivalent of the compiler throwing up its hands and saying &quot;okay, fine, you drive!&quot;    An Example The catalysts of our converstaion were the Parameters and ReturnType utility types built into TypeScript. If you aren't familiar, here they are as defined in es5.d.ts in the TypeScript source type Parameters&lt;T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;  type ReturnType&lt;T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any; The unknown type was introduced in TS 3.0 as a type-safe version of any, so it seemed weird to me that these core utility types are still using any when there are better options. Can't we just replace any with unknonwn in Parameters and ReturnTypes and move on? Actually, no. Try it, and you'll see that something is wrong: type ParametersNoAny&lt;T extends (...args: unknown[]) => unknown> = T extends (...args: infer P) => unknown ? P : never;  type ReturnTypeNoAny&lt;T extends (...args: unknown[]) => unknown> = T extends (...args: unknown[]) => infer R ? R : unknown;  function testFn(a1: string, a2: number): boolean {   return parseInt(a1, 10) === a2; }  type Args = ParametersNoAny&lt;typeof testFn>; // error! type Ret = ReturnTypeNoAny&lt;typeof testFn>; // error! When we try to pass typeof testFn to either of our new utilities, we get this type error: Type '(a1: string, a2: number) => boolean' does not satisfy the constraint '(...args: unknown[]) => unknown'.   Types of parameters 'a1' and 'args' are incompatible.     Type 'unknown' is not assignable to type 'string'. When I first saw this error, it seemed backwards to me. I don't want to assign unknown to string, I want to go the other way, right? I'm passing my string-arged function into these utilities, so I'm trying to assign string where the constraint is unknown, which should accept everything, right? Right?!? Actually, this is a situation where it's helpful to understand contravariance. I wrote a post about covariance and contravariance in TypeScript last year, but I still don't feel like I have a really good grasp of when it's relevant or even in play. But let's make an attempt, using the real-world example of packing boxes. What kind of box do you want? Let's think of ParametersNoAny and ReturnTypeNoAny as you when helping a friend move, and generic argument as the boxes you pack their stuff into. The constraint on the generic parameter (T extends ...) is a request for a box that fits a specific item. And right now, that item is unknown[]: in other words, you want a box that can fit any number of any items. In our terms, that's the set of all possible sets of arguments. There are no functions2 in the set of &quot;functions that accept all possible sets of arguments&quot;! No wonder we get an error when we pass in a function that only accepts a string and a number. The solution here is to say that these functions should take never[] arguments: type ParametersNoAny&lt;T extends (...args: never[]) => unknown> = T extends (...args: infer P) => unknown ? P : never;  type ReturnTypeNoAny&lt;T extends (...args: never[]) => unknown> = T extends (...args: never[]) => infer R ? R : unknown; Now, we are asking for a box that can fit no items. Not a box that must fit no items, but a box that can. To put it another way, you want a box that doesn't need to work for a specific item or set of items: any box will do. Your friend can pass you a box that fits a toaster, or a screwdriver, or a set of tires, and you'll be happy with whatever it is. It works! With these changes, our utility types now work! No errors, and they correctly infer the types we want. type Args = ParametersNoAny&lt;typeof testFn>; // [a1: string, a2: number] type Ret = ReturnTypeNoAny&lt;typeof testFn>; // boolean So glad I finally understand contravariance ... for this week. and yet you must pass it a variable. But that's a different post. ↩︎  expect functions that take (...args: unknown[]), I guess. ↩︎    ",
      "date_published": "2024-03-14T00:00:00.000Z",
      "tags": [
        "typescript",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/2024-07-site-updates/",
      "url": "https://shaky.sh/2024-07-site-updates/",
      "title": "July 2024 Site Updates",
      "content_html": "<p>Not sure what inspired this round of tweaks, but I've made a lot of improvements here this week:</p> <ul> <li>added a home page (used to just be the post list)</li> <li>moved to 11ty 3.0.0 alpha</li> <li>better, more compliant JSON <a href=\"https://shaky.sh/notes.json\">notes feed</a></li> <li>much improved notes views, including local timestamps</li> <li>better microformats on the homepage, article pages, and notes pages</li> <li>built <code>media.shaky.sh</code> (S3 + CloudFront) as a place to host images etc</li> <li>built iOS shortcuts to post a note (via Working Copy) or upload a photo to <code>media.shaky.sh</code>.</li> <li>went down a rabbit-hole about using metadata on S3 objects to store alt text, image dimensions, etc.</li> <li>building &amp; deploying to Netlify from GitHub Actions, instead of directly in Netlify CI</li> <li>syndicating the latest note to <a href=\"https://now.shaky.sh/\">now.shaky.sh</a> (hosted on omg.lol)</li> <li>started several <a href=\"https://slashpages.net/\">slashpages</a> (most not yet linked to)</li> <li>click the d6 in the top right corner!</li> <li>many general styling improvements</li> <li>render <code>mention-of</code> webmentions</li> <li>cleaner styling for webmentions</li> <li>switched to <a href=\"https://catppuccin.com/\">catppuccin theme</a> (for both light and dark modes)</li> <li>added a simple <a href=\"https://umami.is/\">umami</a>-backed upvote capability</li> <li>syndicating notes to mastodon (<a href=\"https://social.lol/\">social.lol</a>) and <a href=\"https://status.lol/\">status.lol</a> as well (via scripts heavily based on <a href=\"https://echo.rknight.me/\">echo</a>).</li> </ul> <p>There's still a bunch of stuff I'd like to do. And hey, maybe I'll even write a few more posts soon.</p> ",
      "content_text": "Not sure what inspired this round of tweaks, but I've made a lot of improvements here this week:  added a home page (used to just be the post list) moved to 11ty 3.0.0 alpha better, more compliant JSON notes feed much improved notes views, including local timestamps better microformats on the homepage, article pages, and notes pages built media.shaky.sh (S3 + CloudFront) as a place to host images etc built iOS shortcuts to post a note (via Working Copy) or upload a photo to media.shaky.sh. went down a rabbit-hole about using metadata on S3 objects to store alt text, image dimensions, etc. building &amp; deploying to Netlify from GitHub Actions, instead of directly in Netlify CI syndicating the latest note to now.shaky.sh (hosted on omg.lol) started several slashpages (most not yet linked to) click the d6 in the top right corner! many general styling improvements render mention-of webmentions cleaner styling for webmentions switched to catppuccin theme (for both light and dark modes) added a simple umami-backed upvote capability syndicating notes to mastodon (social.lol) and status.lol as well (via scripts heavily based on echo).  There's still a bunch of stuff I'd like to do. And hey, maybe I'll even write a few more posts soon. ",
      "date_published": "2024-07-11T00:00:00.000Z",
      "tags": [
        "site-update"
      ]
    },
    {
      "id": "https://shaky.sh/links/ten-years-of-overcast/",
      "url": "https://shaky.sh/links/ten-years-of-overcast/",
      "title": "Ten years of Overcast",
      "content_html": "<p><a href=\"https://marco.org/\">Marco Arment</a>:</p> <blockquote> <p>Today, on the tenth anniversary of Overcast 1.0, I’m happy to launch a complete rewrite and redesign of most of the iOS app, built to carry Overcast into the next decade — and hopefully beyond.</p> </blockquote> <p>I've been using Overcast since the beginning, and it's always been one of my favourite apps. The new UI feeds modern and fresh, and I'm excited to see what Marco has in store next. Specifically, the &quot;new, faster sync engine&quot; for the Apple Watch app will be great; syncing episodes to my watch has been the one frustrating experience I've had with Overcast (although <a href=\"https://heydingus.net/blog/2024/1/overcasts-breakout-new-feature-is-play-with-a-purpose\">the built-in minigame</a> definitely improved that workflow).</p> <p>Congrats on the release, Marco!</p> ",
      "content_text": "Marco Arment:  Today, on the tenth anniversary of Overcast 1.0, I’m happy to launch a complete rewrite and redesign of most of the iOS app, built to carry Overcast into the next decade — and hopefully beyond.  I've been using Overcast since the beginning, and it's always been one of my favourite apps. The new UI feeds modern and fresh, and I'm excited to see what Marco has in store next. Specifically, the &quot;new, faster sync engine&quot; for the Apple Watch app will be great; syncing episodes to my watch has been the one frustrating experience I've had with Overcast (although the built-in minigame definitely improved that workflow). Congrats on the release, Marco! ",
      "date_published": "2024-07-16T00:00:00.000Z"
    },
    {
      "id": "https://shaky.sh/fresh-rss-start/",
      "url": "https://shaky.sh/fresh-rss-start/",
      "title": "A Fresh Start with RSS",
      "content_html": "<p>In the last year or so, I've been getting back into RSS. I was a big user back in the Google Reader days, but after that, I moved to Twitter, and then nothing at all for a while. It's good to be reading thoughtful content sans algorithms again.</p> <p>For months now, I've been using <a href=\"https://netnewswire.com/\">NetNewsWire</a>, which is a solid client on both MacOS and iOS. It's a great experience; other feed clients are perhaps prettier, but NNW gets out of the way and lets me focus on the content.</p> <p>NNW makes it easy to use iCloud to sync feeds between devices, but now that I'm following around 350 feeds, it's pretty slow to update. It also can sync with several services, and so I recently decided to try the one self-hosted option that NNW support: <a href=\"https://freshrss.org/\">FreshRSS</a>.</p> <p>This was a great chance to try <a href=\"https://www.pikapods.com/\">PikaPods</a>, a hosting service that supports a (relatively) small number of managed apps at a very small price. It took just minutes to set up my own FreshRSS pod, at a price of less than $2 a month<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">1</a></sup>. Once the pod was up and running, it was trivial to export an OPML file out of NNW and into FreshRSS, and then connect my FreshRSS account to NNW. It's only been a few days now, but syncing is clearly so much faster.</p> <p>I haven't spent too much time in the FreshRSS UI yet. You could read from there, if you wanted to, but I'm still happy with NNW. It definitely excels at feed management, though. After importing all 300+ feeds, I could easily filter to see only dead links, and unsubscribe from those feeds. There's also a good view of idle feeds: feeds that are still available, but haven't had new items added for several years.</p> <p>I ran into one bug after importing my OPML file: FreshRSS was trying to parse JSON feeds as XML feeds, and was of course erroring. I had to go through these one by one and mark them as JSON feeds in the configuration for each feed. I'm not sure if this is a bug in the OPML import functionality specifically or part of adding a feed in general, but it's a little annoying. When adding new feeds, I've been choosing XML, just in case.</p> <p>There are still a bunch of FreshRSS features I haven't tried<sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">2</a></sup>. But so far, it's been a welcome addition to <a href=\"https://shaky.sh/uses\">my daily workflows</a>.</p> <hr class=\"footnotes-sep\"><section class=\"footnotes\"><ol class=\"footnotes-list\"><li id=\"fn1\" class=\"footnote-item\"><p>And, PikaPods gives you a $5 account credit on signup. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p> </li> <li id=\"fn2\" class=\"footnote-item\"><p>Like <a href=\"https://danq.me/2022/09/27/freshrss-xpath/\">xpath scraping to &quot;create&quot; a feed for a site that doesn't have one</a>. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p> </li> </ol> </section> ",
      "content_text": "In the last year or so, I've been getting back into RSS. I was a big user back in the Google Reader days, but after that, I moved to Twitter, and then nothing at all for a while. It's good to be reading thoughtful content sans algorithms again. For months now, I've been using NetNewsWire, which is a solid client on both MacOS and iOS. It's a great experience; other feed clients are perhaps prettier, but NNW gets out of the way and lets me focus on the content. NNW makes it easy to use iCloud to sync feeds between devices, but now that I'm following around 350 feeds, it's pretty slow to update. It also can sync with several services, and so I recently decided to try the one self-hosted option that NNW support: FreshRSS. This was a great chance to try PikaPods, a hosting service that supports a (relatively) small number of managed apps at a very small price. It took just minutes to set up my own FreshRSS pod, at a price of less than $2 a month1. Once the pod was up and running, it was trivial to export an OPML file out of NNW and into FreshRSS, and then connect my FreshRSS account to NNW. It's only been a few days now, but syncing is clearly so much faster. I haven't spent too much time in the FreshRSS UI yet. You could read from there, if you wanted to, but I'm still happy with NNW. It definitely excels at feed management, though. After importing all 300+ feeds, I could easily filter to see only dead links, and unsubscribe from those feeds. There's also a good view of idle feeds: feeds that are still available, but haven't had new items added for several years. I ran into one bug after importing my OPML file: FreshRSS was trying to parse JSON feeds as XML feeds, and was of course erroring. I had to go through these one by one and mark them as JSON feeds in the configuration for each feed. I'm not sure if this is a bug in the OPML import functionality specifically or part of adding a feed in general, but it's a little annoying. When adding new feeds, I've been choosing XML, just in case. There are still a bunch of FreshRSS features I haven't tried2. But so far, it's been a welcome addition to my daily workflows. And, PikaPods gives you a $5 account credit on signup. ↩︎  Like xpath scraping to &quot;create&quot; a feed for a site that doesn't have one. ↩︎    ",
      "date_published": "2024-07-17T00:00:00.000Z",
      "tags": [
        "tech"
      ]
    },
    {
      "id": "https://shaky.sh/fluent-interfaces-in-typescript/",
      "url": "https://shaky.sh/fluent-interfaces-in-typescript/",
      "title": "Fluent Interfaces in TypeScript",
      "content_html": "<aside class=\"callout idea-callout\"> <h3 id=\"prefer-to-watch%3F\" tabindex=\"-1\">Prefer to Watch?</h3> <p>You can <a href=\"https://www.youtube.com/watch?v=bH61wRMqp-o\">learn about fluent interfaces in the video version of this article</a>.</p> </aside> <p>Even if you don't recognize the term, you've more than likely used a <a href=\"https://en.wikipedia.org/wiki/Fluent_interface\">Fluent Interface</a> before. The simplest definition is, method chaining<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">1</a></sup>. I think jQuery was my introduction to fluent interfaces. Remember writing code like this?</p> <pre class=\"language-js\"><code class=\"language-js\"><span class=\"highlight-line\"><span class=\"token function\">$</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"#toggleButton\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">click</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span></span> <span class=\"highlight-line\">    <span class=\"token function\">$</span><span class=\"token punctuation\">(</span><span class=\"token string\">\".box\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">        <span class=\"token punctuation\">.</span><span class=\"token function\">toggle</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">        <span class=\"token punctuation\">.</span><span class=\"token function\">css</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"background-color\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"red\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">        <span class=\"token punctuation\">.</span><span class=\"token function\">css</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"color\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"blue\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">        <span class=\"token punctuation\">.</span><span class=\"token function\">text</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">_<span class=\"token punctuation\">,</span> oldText</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>oldText<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> - Toggled!</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">        <span class=\"token punctuation\">.</span><span class=\"token function\">append</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"&lt;p>Additional text appended!&lt;/p>\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>jQuery was first released shortly after I started learning JavaScript. Of course, mainly, I loved how it made the DOM accessible to me. But as a very junior programmer, the concept of chaining methods together to create more complex behaviour was fascinating.</p> <p>A more current example that we're probably all familiar with is assertion libraries:</p> <pre class=\"language-js\"><code class=\"language-js\"><span class=\"highlight-line\"><span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>myObj<span class=\"token punctuation\">.</span>permissions<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>not<span class=\"token punctuation\">.</span><span class=\"token function\">toContain</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"repo:delete\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>Currently in my evolution as a software engineer, I try to spend a lot of time thinking about the consumption experience of my code: how can I make it easy for other engineers<sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">2</a></sup> to use the functions, libraries, and APIs I write?</p> <p>A <strong>fluent interface</strong> is one of the tools in that toolbox. And paired with good types, it becomes even stronger. So let's look at a few patterns for creating strongly-typed fluent interfaces in TypeScript.</p> <h2 id=\"a-basic-querybuilder\" tabindex=\"-1\">A Basic QueryBuilder</h2> <p>Here's a basic example of a class with a fluent interface:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">QueryBuilder</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">private</span> fields<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">private</span> wheres<span class=\"token operator\">:</span> Record<span class=\"token operator\">&lt;</span><span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> <span class=\"token builtin\">string</span><span class=\"token operator\">></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">private</span> table<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span> <span class=\"token operator\">=</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token function\">select</span><span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>columns<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>fields <span class=\"token operator\">=</span> columns<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token function\">from</span><span class=\"token punctuation\">(</span>table<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>table <span class=\"token operator\">=</span> table<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token function\">where</span><span class=\"token punctuation\">(</span>column<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> value<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>wheres<span class=\"token punctuation\">[</span>column<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> value<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span>     <span class=\"token keyword\">return</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">SELECT </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>fields<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">\", \"</span><span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> FROM </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>table<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> WHERE </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>Object<span class=\"token punctuation\">.</span><span class=\"token function\">entries</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>wheres<span class=\"token punctuation\">)</span> <span class=\"highlight-line\">      <span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>k<span class=\"token punctuation\">,</span> v<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>k<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> = </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>v<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span></span>       <span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">\" AND \"</span><span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">;</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>It's simple, but we can see the main tenets of fluent interfaces here. The <code>select</code>, <code>from</code>, and <code>where</code> methods all <code>return this</code>, which allows us to chain method calls together. Of course, since these methods return their object (and therefore can't return anything else), they must perform some side effect in order to be worth calling. Usually, that's managing some internal object state; here, we're setting the values of the <code>fields</code> and <code>wheres</code> properties.</p> <p>We also need a way to terminate the chaining. And we've made the <code>build</code> method to be the last link in the chain. Instead of returning the object, it uses the object state to create the SQL query.</p> <p>So, what does it look like to use this?</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">const</span> query <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">QueryBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">select</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"name\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"email\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">from</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"users\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">where</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"id\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"1\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>(<a href=\"https://www.typescriptlang.org/play/?#code/MYGwhgzhAECKCuBTATgTwELwJYgCYugG8AoaaAB2SwDcwAXRaAMy0TwgC5oI6qA7AOYBtALrQAvNFEBuUhSq0G0AO4ALFIk7QASomAB7ZLgA8PfgIA03XlkEA+CUQC+sspRr1GdMACMQiLjNbAUcAclDZOQg2PToACgA6JIMQeABbPi0gwVEASiI5MjpVLAgEljZcGEkU9MzXMmhkRDp4ZD5oYtKGp2I5JmR9NLjvPwDrc3ySRs6SstH-RwXEBrJm1vbZ7rleuTUNONqMwJtBK1pU8eyBKcKtsv3miCEjvjFJC6RVppa2jq6ID0+mQfNg8HFbjN1n9oAADADKAFEADKIgDCABVoAASQgA8qsdgJABW+lscQARFYKbknNAAGLaADyAFkcXi5gllnSAOoACUR2kR7KZPmJsQSiD4Nk0I05j00uTuZASaTA5DicSEAGtziJ8uIHLDcdq6ZJcdQnLClTMVaTyRToABBAByABFoDSXLCgbsDJk6NAAI5INCOPiIZRwUMYMH4ZAQuQJaL+YDxCl8MBpRBUz2INU4GlJgZDSnwaLICBFlUKylYXC5ikARmr0ASoJwuAhkWI-og+n8CRA+gEcRDKFQuWkQA\">TS Playground</a>)</p> <p>This is a fairly fluent interface for building queries. It reads about as close to SQL as you could get in JavaScript, which I'd say makes it a decent DSL.</p> <p>However, this leaves a lot to be desired for types; so let's look at another example.</p> <h2 id=\"piping\" tabindex=\"-1\">Piping</h2> <p>This implementation is short, but it packs a lot in.</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">function</span> <span class=\"token generic-function\"><span class=\"token function\">pipe</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token constant\">A</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">B</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token function-variable function\">fn</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>a<span class=\"token operator\">:</span> <span class=\"token constant\">A</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token constant\">B</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token keyword\">function</span> <span class=\"token function\">run</span><span class=\"token punctuation\">(</span>a<span class=\"token operator\">:</span> <span class=\"token constant\">A</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> <span class=\"token function\">fn</span><span class=\"token punctuation\">(</span>a<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  run<span class=\"token punctuation\">.</span>pipe <span class=\"token operator\">=</span> <span class=\"token operator\">&lt;</span><span class=\"token constant\">C</span><span class=\"token operator\">></span><span class=\"token punctuation\">(</span><span class=\"token function-variable function\">fn2</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>b<span class=\"token operator\">:</span> <span class=\"token constant\">B</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token constant\">C</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span></span> <span class=\"highlight-line\">    <span class=\"token function\">pipe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>a<span class=\"token operator\">:</span> <span class=\"token constant\">A</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span></span> <span class=\"highlight-line\">      <span class=\"token function\">fn2</span><span class=\"token punctuation\">(</span><span class=\"token function\">fn</span><span class=\"token punctuation\">(</span>a<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token keyword\">return</span> run<span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span></code></pre> <p>This <code>pipe</code> function allows you to chain together other functions to create one &quot;super-function&quot;, which passes an argument through every link in the chain.</p> <p>The first thing you might notice is that we never <code>return this</code>. In fact, there isn't a class, or even an object, in sight! This time, we're using closure to store our state, in the form of one (<code>fn</code>) or two (<code>fn2</code>) function arguments.</p> <p><code>pipe</code> takes a single argument: a function that takes an <code>A</code> and returns a <code>B</code>. And it returns a function (<code>run</code>) that does the same thing!</p> <p>However, the special sauce is the <code>run.pipe</code> assignment. We assign a function that takes a <code>B</code>-to-<code>C</code> function  as its argument, and we call <code>pipe</code> on that, nesting a call to our first argument in there! So <code>fn2(fn(arg))</code> is a call that goes from type <code>A</code> to type <code>C</code>, which gives us everything we need to <strong>type-safely</strong> chain a list of function calls.</p> <p>Make sense? Sometimes, only an example will do:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">const</span> stringToDateAndTime <span class=\"token operator\">=</span> <span class=\"token function\">pipe</span><span class=\"token punctuation\">(</span>Date<span class=\"token punctuation\">.</span>parse<span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">pipe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>n<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span>n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">pipe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>d<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> d<span class=\"token punctuation\">.</span><span class=\"token function\">toISOString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">pipe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>s<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> s<span class=\"token punctuation\">.</span><span class=\"token function\">split</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"T\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">pipe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>a<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> date<span class=\"token operator\">:</span> a<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> time<span class=\"token operator\">:</span> a<span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">const</span> result <span class=\"token operator\">=</span> <span class=\"token function\">stringToDateAndTime</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Jan 1, 2024\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// result = { date: \"2024-01-01\", time: \"05:00:00.000Z\" }</span></span></code></pre> <p>We can start the chain by calling <code>pipe</code> and passing it a function. And then we continue the chain by repeatedly calling <code>.pipe</code> with other functions. Each of these functions will receive a strongly-typed argument, based on the return type of the previous link in the chain. And the result, <code>stringToDateAndTime</code>, is a function that takes a string, parses it to a date, splits the date into a date and time, and returns an object. You can <a href=\"https://www.typescriptlang.org/play/?#code/GYVwdgxgLglg9mABABxsgpgHgIIBpEBCAfABTBgBciJAhldgJSIC8RhTA3gFCKKiSwEiAE7ha9Tj14j0UEMKTlaDANxSAvlymiwAOlQYWiTAGFcpcgCYqJAEZUCTVohNOiU3gfQlxiRi3dpaSsyMGUGD0RVLV5hWXkkHTVNLggEAGcoREzhGDAAcwAVOAARGih0bDAAE0KYAFt0Iy8SMor9GmF09AjefTRvEjA3RDB0AHdENu9h3sR+jB9qkerdKDgASQBlAHktqFyCkgY5hcH0kfTddOQAGxgoEgAiQqeTqTOfGhGSDkRq8roKg0ADaAAYALr4WCNYEggCMEMQ6hOalSGSycXSIFuWWY2QOeSKpUBVVqDW8TwAUjQkPD8JYwZYACxvNFpMDpOC3dC6W5wfIkLE4qCqIA\">play with this example in the TypeScript Playground</a>.</p> <p>I like this example because of its elegance: the generic types effortlessly allow the function types to flow through. It's also cool to see <a href=\"https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html\">state captured via closure rather than objects</a>.</p> <p>But mainly, it's a good reminder that fluent interfaces often appear as though they are performing actions, but actually are <em>enqueuing</em> actions.</p> <ul> <li>In our first example, methods like <code>select</code> and <code>from</code> do not actually query a database or even form a query; until we call <code>build</code>, nothing really happens (outside the object).</li> <li>It's the same with <code>pipe</code>: we can <code>pipe</code> in new functions all day, but until we stop and actually call the resulting function with an argument, none of those piped functions are actually run.</li> </ul> <p>I find this to be a good cue for situations where a fluent interface is useful: any time you want to build up a lot of configuration or perform a set of actions that result in a single output, you might find that a fluent interface is a good choice.</p> <h2 id=\"all-together-now\" tabindex=\"-1\">All Together Now</h2> <p>Finally, let's look at a stronger version of the <code>QueryBuilder</code> that we started with. This example is a simplified version of a <a href=\"https://github.com/andrew8088/disco/blob/main/packages/why/src/selector.ts\">toy project of mine</a>, which aims to be a SQL query builder with incredibly robust types. You can check out the full version on GitHub, but this stripped-down example shows the main mechanics:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">QueryBuilder<span class=\"token operator\">&lt;</span>Tables <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">{</span> <span class=\"token punctuation\">[</span>tableName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> BaseTable <span class=\"token punctuation\">}</span><span class=\"token operator\">></span></span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token generic-function\"><span class=\"token function\">table</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token constant\">N</span> <span class=\"token keyword\">extends</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> BaseTable<span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">QueryBuilder<span class=\"token operator\">&lt;</span>Tables <span class=\"token operator\">&amp;</span> <span class=\"token punctuation\">{</span> <span class=\"token punctuation\">[</span><span class=\"token constant\">X</span> <span class=\"token keyword\">in</span> <span class=\"token constant\">N</span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> <span class=\"token constant\">T</span> <span class=\"token punctuation\">}</span><span class=\"token operator\">></span></span><span class=\"token punctuation\">(</span></span> <span class=\"highlight-line\">      <span class=\"token comment\">/* copy state over here */</span></span> <span class=\"highlight-line\">    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token function\">select</span><span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>cols<span class=\"token operator\">:</span> Columns<span class=\"token operator\">&lt;</span>Tables<span class=\"token operator\">></span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token comment\">// implement here</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">  <span class=\"token generic-function\"><span class=\"token function\">where</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token constant\">K</span> <span class=\"token keyword\">extends</span> Columns<span class=\"token operator\">&lt;</span>Tables<span class=\"token operator\">>></span></span></span><span class=\"token punctuation\">(</span>col<span class=\"token operator\">:</span> <span class=\"token constant\">K</span><span class=\"token punctuation\">,</span> value<span class=\"token operator\">:</span> Flat<span class=\"token operator\">&lt;</span>Tables<span class=\"token operator\">></span><span class=\"token punctuation\">[</span><span class=\"token constant\">K</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">    <span class=\"token comment\">// implement here</span></span> <span class=\"highlight-line\">    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token comment\">// Helper Types</span></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">BaseTable</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">[</span>colName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span> <span class=\"token operator\">|</span> <span class=\"token builtin\">number</span> <span class=\"token operator\">|</span> <span class=\"token builtin\">boolean</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Columns<span class=\"token operator\">&lt;</span>Tables <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">{</span> <span class=\"token punctuation\">[</span>tableName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> BaseTable <span class=\"token punctuation\">}</span><span class=\"token operator\">></span></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">[</span><span class=\"token constant\">K</span> <span class=\"token keyword\">in</span> <span class=\"token keyword\">keyof</span> Tables<span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> <span class=\"token constant\">K</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\"><span class=\"token builtin\">string</span></span> <span class=\"token operator\">?</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">keyof</span> Tables<span class=\"token punctuation\">[</span><span class=\"token constant\">K</span><span class=\"token punctuation\">]</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\"><span class=\"token builtin\">string</span></span> <span class=\"token operator\">?</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token constant\">K</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">.</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">keyof</span> Tables<span class=\"token punctuation\">[</span><span class=\"token constant\">K</span><span class=\"token punctuation\">]</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">[</span><span class=\"token keyword\">keyof</span> Tables<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Flat<span class=\"token operator\">&lt;</span>Tables <span class=\"token keyword\">extends</span> <span class=\"token punctuation\">{</span> <span class=\"token punctuation\">[</span>tableName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> BaseTable <span class=\"token punctuation\">}</span><span class=\"token operator\">></span></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">[</span><span class=\"token constant\">K</span> <span class=\"token keyword\">in</span> Columns<span class=\"token operator\">&lt;</span>Tables<span class=\"token operator\">></span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> Tables<span class=\"token punctuation\">[</span><span class=\"token constant\">K</span> <span class=\"token keyword\">extends</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">infer</span> <span class=\"token constant\">T</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">.</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">infer</span> _<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token operator\">?</span> <span class=\"token constant\">T</span> <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token constant\">K</span> <span class=\"token keyword\">extends</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">infer</span> _<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">.</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">infer</span> <span class=\"token constant\">C</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span></span> <span class=\"highlight-line\">    <span class=\"token operator\">?</span> <span class=\"token constant\">C</span></span> <span class=\"highlight-line\">    <span class=\"token operator\">:</span> <span class=\"token builtin\">never</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></span></code></pre> <p>The main thing I want to highlight here is that <code>table</code> function. It's only purpose is to add new tables to the <code>Tables</code> type, so we can get good suggestions and typing when using <code>select</code> and <code>where</code>. It does this by returning a new <code>QueryBuilder</code> instance. It's difficult (actually, impossible, I think) to mutate the generic types of an object as you interact with it. So instead, we copy the state over to a new instance and give the new object the new types we want.</p> <p>(The <code>Column&lt;T&gt;</code> and <code>Flat&lt;T&gt;</code> types are mainly sugar, so I won't explain them here, but do give them a test-drive, they're a good time.)</p> <p>With this <code>QueryBuilder</code>, we can write code like this:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> q <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">QueryBuilder<span class=\"token operator\">&lt;</span><span class=\"token punctuation\">{</span> user<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span> name<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span> <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span><span class=\"token operator\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"></span> <span class=\"highlight-line\">q<span class=\"token punctuation\">.</span><span class=\"token function\">select</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"user.id\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"user.name\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">where</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"user.name\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"andrew\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">where</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"user.id\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">3</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre> <p>We initialize a <code>QueryBuilder</code> instance that only knows about our <code>user</code> table; from there we can select and filter on user columns. And we do have strong types on this! For example:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\">q<span class=\"token punctuation\">.</span><span class=\"token function\">select</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"user.id\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"user.age\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\"><span class=\"token comment\">//                   ^^^^^^^^</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// Argument of type '\"user.age\"' is not assignable</span></span> <span class=\"highlight-line\"><span class=\"token comment\">//  to parameter of type '\"user.id\" | \"user.name\"'.</span></span></code></pre> <p>Or</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\">q<span class=\"token punctuation\">.</span><span class=\"token function\">where</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"user.name\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\"><span class=\"token comment\">//                   ^^^^^^^^^^</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// Argument of type 'Date' is not assignable</span></span> <span class=\"highlight-line\"><span class=\"token comment\">//  to parameter of type 'string'.</span></span></code></pre> <p>But then, we can add an additional table, and query that as well:</p> <pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"highlight-line\">q</span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">select</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"user.id\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"user.name\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token generic-function\"><span class=\"token function\">table</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token string\">\"widget\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> widgetId<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span> userId<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span> <span class=\"token punctuation\">}</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">select</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"widget.widgetId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"widget.userId\"</span><span class=\"token punctuation\">)</span></span> <span class=\"highlight-line\">  <span class=\"token punctuation\">.</span><span class=\"token function\">where</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"widget.widgetId\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">12</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span> <span class=\"highlight-line\"><span class=\"token comment\">//                          ^^</span></span> <span class=\"highlight-line\"><span class=\"token comment\">// Argument of type 'number' is not assignable</span></span> <span class=\"highlight-line\"><span class=\"token comment\">//  to parameter of type 'string'.</span></span></code></pre> <p>(<a href=\"https://www.typescriptlang.org/play/?#code/MYGwhgzhAECKCuBTATgTwELwJYgCYoB4AVMAIxERkQA8AXRAO1xgG9oBtWsigOTAFtEALmgRayLAwDmAXRHpIiEuUTQAvgD5oLAFDRoXFQR7Qa9JjDETpAGmhFTdRs2gKIS7og0AKAJTa9fWhkRFp4ZAZoBkQAdzgkNEwcfGRiTxgAMm0OAA1oSWgeOXt1H18AbkC1HUD3CmBabwA6FuAAexAIEQBhDvh+Bgg0lQgNdhl-XSDoAHoZ-P4ABwpBBlpoAAsURED9ELCIgw2sCEr9asCYrZCCAGlHcxdekH7B4YpRn3aQEVu7ADcwC9hNAAGLgWjvShjW4TALTOYLZaIVbra47ab7cKRWjHU5VHQXREACUQIEWKHsqApEB0tGpqjcHhU0AAvPCON8+IIRFZJLJeeJ+dAAD5RfqkSli0htDqIMAMSpqSp0hnQZ6vIbKD4PZysDiGXgCEF86TFJna1SaNkc9j3AoAa0QqDaADN7OlivczHrRELpNAAPzQbxOl3uy0QO0yXUWP3WKRB6AAAwAJCxbmomumw26PSNo2pk9ARNF-ih-KXEOXkEr2LmI56VfSKWCIVCqE442xOJ5uSb-QLXIpLaUbVMOPbIhqBlr0hpipG7bGXGmWJJXZSiFn0xvKQB9ItJhxVmsyZc+uNrvfIaCH7Prhib2-dIu7JPdd+nlAyJUqnQ0IsbTIOs7SDOsACONrRHECAoBg2B4IQbDwO4yAiGwWC4KWEooOUUTGoKCbqKUfgqhBTR1IgDTeAARKhKBNFhtF2PRaFNAwxq0b4gRNFc2x0QxyAcVxrEKrgIQxNxvH8SEgnscxdgAMw8foTSGogBC0TEWFSKELHZDpuB6bQACS2Hxvy+FCeZOH8JKt6aH4vFUTR2m6aEfEeWZuAGe5xmeTZvmqdAfHonRRkmV5AU+QZACMABMFQ6EAA\">TS Playground</a>)</p> <p>This example doesn't actually implement the internals (again, see <a href=\"https://github.com/andrew8088/disco/blob/main/packages/why/src/selector.ts\">a more complete example on GitHub</a>) but it shows how TypeScript can enable non-trivial fluent interfaces that are a delight to use as a library consumer.</p> <h2 id=\"inspiration\" tabindex=\"-1\">Inspiration</h2> <p>I've taken a lot of inspiration from <a href=\"https://kysely.dev/docs/playground\">Kysely</a> for these <code>QueryBuilder</code> examples. If there are other examples of fluent interfaces that you find elegant or ergonomic, I'd love to hear about them!</p> <hr class=\"footnotes-sep\"><section class=\"footnotes\"><ol class=\"footnotes-list\"><li id=\"fn1\" class=\"footnote-item\"><p>Actually, Martin Fowler, the coiner of the term, says <a href=\"https://www.martinfowler.com/bliki/FluentInterface.html\">a fluent interface is primarily about building a DSL</a>, and not just method chaining. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p> </li> <li id=\"fn2\" class=\"footnote-item\"><p>Often, myself 6 months from now. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p> </li> </ol> </section> ",
      "content_text": " Prefer to Watch? You can learn about fluent interfaces in the video version of this article.  Even if you don't recognize the term, you've more than likely used a Fluent Interface before. The simplest definition is, method chaining1. I think jQuery was my introduction to fluent interfaces. Remember writing code like this? $(\"#toggleButton\").click(() =>     $(\".box\")         .toggle()         .css(\"background-color\", \"red\")         .css(\"color\", \"blue\")         .text((_, oldText) => `${oldText} - Toggled!`)         .append(\"&lt;p>Additional text appended!&lt;/p>\") ); jQuery was first released shortly after I started learning JavaScript. Of course, mainly, I loved how it made the DOM accessible to me. But as a very junior programmer, the concept of chaining methods together to create more complex behaviour was fascinating. A more current example that we're probably all familiar with is assertion libraries: expect(myObj.permissions).not.toContain(\"repo:delete\"); Currently in my evolution as a software engineer, I try to spend a lot of time thinking about the consumption experience of my code: how can I make it easy for other engineers2 to use the functions, libraries, and APIs I write? A fluent interface is one of the tools in that toolbox. And paired with good types, it becomes even stronger. So let's look at a few patterns for creating strongly-typed fluent interfaces in TypeScript. A Basic QueryBuilder Here's a basic example of a class with a fluent interface: class QueryBuilder {   private fields: string[] = [];   private wheres: Record&lt;string, string> = {};   private table: string = '';    select(...columns: string[]) {     this.fields = columns;     return this;   }    from(table: string) {     this.table = table;     return this;   }    where(column: string, value: string) {     this.wheres[column] = value;     return this;   }    build() {     return `SELECT ${this.fields.join(\", \")} FROM ${this.table} WHERE ${Object.entries(this.wheres)       .map(([k, v]) => `${k} = ${v}`)       .join(\" AND \")};`;   } } It's simple, but we can see the main tenets of fluent interfaces here. The select, from, and where methods all return this, which allows us to chain method calls together. Of course, since these methods return their object (and therefore can't return anything else), they must perform some side effect in order to be worth calling. Usually, that's managing some internal object state; here, we're setting the values of the fields and wheres properties. We also need a way to terminate the chaining. And we've made the build method to be the last link in the chain. Instead of returning the object, it uses the object state to create the SQL query. So, what does it look like to use this? const query = new QueryBuilder()   .select(\"name\", \"email\")   .from(\"users\")   .where(\"id\", \"1\")   .build(); (TS Playground) This is a fairly fluent interface for building queries. It reads about as close to SQL as you could get in JavaScript, which I'd say makes it a decent DSL. However, this leaves a lot to be desired for types; so let's look at another example. Piping This implementation is short, but it packs a lot in. function pipe&lt;A, B>(fn: (a: A) => B) {   function run(a: A) {     return fn(a);   }    run.pipe = &lt;C>(fn2: (b: B) => C) =>     pipe((a: A) =>       fn2(fn(a))     );    return run; } This pipe function allows you to chain together other functions to create one &quot;super-function&quot;, which passes an argument through every link in the chain. The first thing you might notice is that we never return this. In fact, there isn't a class, or even an object, in sight! This time, we're using closure to store our state, in the form of one (fn) or two (fn2) function arguments. pipe takes a single argument: a function that takes an A and returns a B. And it returns a function (run) that does the same thing! However, the special sauce is the run.pipe assignment. We assign a function that takes a B-to-C function  as its argument, and we call pipe on that, nesting a call to our first argument in there! So fn2(fn(arg)) is a call that goes from type A to type C, which gives us everything we need to type-safely chain a list of function calls. Make sense? Sometimes, only an example will do: const stringToDateAndTime = pipe(Date.parse)   .pipe((n) => new Date(n))   .pipe((d) => d.toISOString())   .pipe((s) => s.split(\"T\"))   .pipe((a) => ({ date: a[0], time: a[1] }));  const result = stringToDateAndTime(\"Jan 1, 2024\"); // result = { date: \"2024-01-01\", time: \"05:00:00.000Z\" } We can start the chain by calling pipe and passing it a function. And then we continue the chain by repeatedly calling .pipe with other functions. Each of these functions will receive a strongly-typed argument, based on the return type of the previous link in the chain. And the result, stringToDateAndTime, is a function that takes a string, parses it to a date, splits the date into a date and time, and returns an object. You can play with this example in the TypeScript Playground. I like this example because of its elegance: the generic types effortlessly allow the function types to flow through. It's also cool to see state captured via closure rather than objects. But mainly, it's a good reminder that fluent interfaces often appear as though they are performing actions, but actually are enqueuing actions.  In our first example, methods like select and from do not actually query a database or even form a query; until we call build, nothing really happens (outside the object). It's the same with pipe: we can pipe in new functions all day, but until we stop and actually call the resulting function with an argument, none of those piped functions are actually run.  I find this to be a good cue for situations where a fluent interface is useful: any time you want to build up a lot of configuration or perform a set of actions that result in a single output, you might find that a fluent interface is a good choice. All Together Now Finally, let's look at a stronger version of the QueryBuilder that we started with. This example is a simplified version of a toy project of mine, which aims to be a SQL query builder with incredibly robust types. You can check out the full version on GitHub, but this stripped-down example shows the main mechanics: class QueryBuilder&lt;Tables extends { [tableName: string]: BaseTable }> {   table&lt;N extends string, T extends BaseTable>() {     return new QueryBuilder&lt;Tables &amp; { [X in N]: T }>(       /* copy state over here */     );   }    select(...cols: Columns&lt;Tables>[]) {     // implement here     return this;   }    where&lt;K extends Columns&lt;Tables>>(col: K, value: Flat&lt;Tables>[K]) {     // implement here     return this;   } }  // Helper Types type BaseTable = {   [colName: string]: string | number | boolean; };  type Columns&lt;Tables extends { [tableName: string]: BaseTable }> = {   [K in keyof Tables]: K extends string ? (keyof Tables[K] extends string ? `${K}.${keyof Tables[K]}` : never) : never; }[keyof Tables];  type Flat&lt;Tables extends { [tableName: string]: BaseTable }> = {   [K in Columns&lt;Tables>]: Tables[K extends `${infer T}.${infer _}` ? T : never][K extends `${infer _}.${infer C}`     ? C     : never]; }; The main thing I want to highlight here is that table function. It's only purpose is to add new tables to the Tables type, so we can get good suggestions and typing when using select and where. It does this by returning a new QueryBuilder instance. It's difficult (actually, impossible, I think) to mutate the generic types of an object as you interact with it. So instead, we copy the state over to a new instance and give the new object the new types we want. (The Column&lt;T&gt; and Flat&lt;T&gt; types are mainly sugar, so I won't explain them here, but do give them a test-drive, they're a good time.) With this QueryBuilder, we can write code like this: export const q = new QueryBuilder&lt;{ user: { id: number; name: string } }>();  q.select(\"user.id\", \"user.name\")   .where(\"user.name\", \"andrew\")   .where(\"user.id\", 3); We initialize a QueryBuilder instance that only knows about our user table; from there we can select and filter on user columns. And we do have strong types on this! For example: q.select(\"user.id\", \"user.age\") //                   ^^^^^^^^ // Argument of type '\"user.age\"' is not assignable //  to parameter of type '\"user.id\" | \"user.name\"'. Or q.where(\"user.name\", new Date()) //                   ^^^^^^^^^^ // Argument of type 'Date' is not assignable //  to parameter of type 'string'. But then, we can add an additional table, and query that as well: q   .select(\"user.id\", \"user.name\")   .table&lt;\"widget\", { widgetId: string; userId: number }>()   .select(\"widget.widgetId\", \"widget.userId\")   .where(\"widget.widgetId\", 12); //                          ^^ // Argument of type 'number' is not assignable //  to parameter of type 'string'. (TS Playground) This example doesn't actually implement the internals (again, see a more complete example on GitHub) but it shows how TypeScript can enable non-trivial fluent interfaces that are a delight to use as a library consumer. Inspiration I've taken a lot of inspiration from Kysely for these QueryBuilder examples. If there are other examples of fluent interfaces that you find elegant or ergonomic, I'd love to hear about them! Actually, Martin Fowler, the coiner of the term, says a fluent interface is primarily about building a DSL, and not just method chaining. ↩︎  Often, myself 6 months from now. ↩︎    ",
      "date_published": "2024-07-23T00:00:00.000Z",
      "tags": [
        "typescript",
        "eng"
      ]
    },
    {
      "id": "https://shaky.sh/bell-mobility-scam/",
      "url": "https://shaky.sh/bell-mobility-scam/",
      "title": "Bell Mobility Scam Call",
      "content_html": "<p>I recieved a phone call yesterday that I didn't immediately recognize as a scam call. I want to document it here in case anyone else comes across it.</p> <p>The backstory here is that, for the last month, I've been ignoring a few calls a week from a phone number that has the same area code and <a href=\"https://en.wikipedia.org/wiki/Telephone_prefix\">prefix</a> as my own number. I answered one call a few weeks back, and it was Bell Mobility (my cell provider), offering a device upgrade. I explained to them that I had just upgraded my phone at the Apple Stor and wasn't interested in upgrading yet again.</p> <p>Since then, I'd been ignoring that number, but when it called again yesterday I answered. I was actually hoping they could help me combine by cell phone bill and internet bill into one (since I use Bell for both).</p> <p>However, the salesperson told me he was from Bell, and told me that I was going to receive a 30% discount from my monthly bill for the next year, because I've paid my bill on time every month for so many years. This seemed unreasonably altruistic, but so far, I didn't really suspect much because he wasn't asking for any information. He did ask about how much my monthly bill currently is, which raised my suspicions.</p> <p>But then he went on to say that as a loyal customer, I was elligible to receive either a new Apple Watch or iPad. This really put me on guard, so I asked a few more details about the watch, and searched online while he talked and found that this is a common scam, specifically with Bell Mobility.</p> <p>I also asked for some details about this promotion, and was told that Bell is doing this to retain customers and remain competitive.</p> <p>At this point, the guy was asking me for a postal code, and I told him I don't give out personal info over the phone as a rule. He commended me on this, but reminded me that he isn't selling anything and I'm not buying anything. I insisted that I wouldn't do anything over the phone, and asked if I could get this offer by going into my local Bell store. He mumbled something and then hung up.</p> <p>Careful out there, folks. I really hate that so many daily interactions have to be treated with such suspicion.</p> ",
      "content_text": "I recieved a phone call yesterday that I didn't immediately recognize as a scam call. I want to document it here in case anyone else comes across it. The backstory here is that, for the last month, I've been ignoring a few calls a week from a phone number that has the same area code and prefix as my own number. I answered one call a few weeks back, and it was Bell Mobility (my cell provider), offering a device upgrade. I explained to them that I had just upgraded my phone at the Apple Stor and wasn't interested in upgrading yet again. Since then, I'd been ignoring that number, but when it called again yesterday I answered. I was actually hoping they could help me combine by cell phone bill and internet bill into one (since I use Bell for both). However, the salesperson told me he was from Bell, and told me that I was going to receive a 30% discount from my monthly bill for the next year, because I've paid my bill on time every month for so many years. This seemed unreasonably altruistic, but so far, I didn't really suspect much because he wasn't asking for any information. He did ask about how much my monthly bill currently is, which raised my suspicions. But then he went on to say that as a loyal customer, I was elligible to receive either a new Apple Watch or iPad. This really put me on guard, so I asked a few more details about the watch, and searched online while he talked and found that this is a common scam, specifically with Bell Mobility. I also asked for some details about this promotion, and was told that Bell is doing this to retain customers and remain competitive. At this point, the guy was asking me for a postal code, and I told him I don't give out personal info over the phone as a rule. He commended me on this, but reminded me that he isn't selling anything and I'm not buying anything. I insisted that I wouldn't do anything over the phone, and asked if I could get this offer by going into my local Bell store. He mumbled something and then hung up. Careful out there, folks. I really hate that so many daily interactions have to be treated with such suspicion. ",
      "date_published": "2024-08-01T13:39:00.000Z",
      "tags": [
        "blaugust"
      ]
    },
    {
      "id": "https://shaky.sh/hello-blaugust-2024/",
      "url": "https://shaky.sh/hello-blaugust-2024/",
      "title": "Hello Blaugust 2024",
      "content_html": "<p>Last night, I discovered <a href=\"https://aggronaut.com/2024/07/12/blaugust-2024-is-coming/\">Blaugust</a>! I've been wanting to write more, and this seems like a great way to push myself to do exactly that. I doubt I'll write 31 posts this month ... I'm already a day or so behind. However, writing even 5 posts this month will definitely be a record for me.</p> <p>The suggested prompt for the first day is to introduce yourself, so that's what this is! (I guess technically my first &quot;blaugust&quot; post was about a scam call).</p> <p>I'm Andrew! I'm a software engineer from Toronto, Canada. For me, writing code isn't just about solving the problem. It's about understanding the domain and finding an elegant solution that, ideal, makes solving the next problem just a little bit easier. I'm passionate about the craft of writing code, and about finding good patterns and conventions that can make building tools simpler. I've had jobs as both a primarily front-end and primarily back-end developer. Right now, I consider myself to be pretty full-stack, and work on the server and client most days. But I think I'll always be a little more comfortable on the back-end. I worked in fintech for a while, but now I work in education tech. I've worked mostly in JavaScript or TypeScript environments. These days I enjoy discovering and sharing TypeScript patterns that improve developer experience.</p> <p>For most of my time on the internet, I've been writing or making videos about programming. Originally, I did this for <a href=\"https://tutsplus.com/authors/andrew-burgess\">Tuts+</a>. Apparently, they're still updating and republishing some of my old articles!<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">1</a></sup> A few years back, I started making videos again, this time on <a href=\"https://www.youtube.com/c/andrew8088\">my own YouTube channel</a>. And now I'm trying to write here more often.</p> <p>So far, this blog has been mostly technical, it's been programming-related. However, that's not the only thing I think about. I'm a Christian, and am always learning more about what it looks like to have a deeper relationship with God, and to live out my faith. Christianity is supposed to be primarily about that relationship, and not about a lot of the other stuff that gets labeled as &quot;Christian&quot; these days. Religion has done a lot of harm to a lot of people in the name of Christianity. I'm also interested in topics like productivity and having healthy relationships.</p> <p>However, I think I'll stick to writing about technical stuff for now, at least publicly. I'm excited to be participating in Blaugust and look forward to discovering new bloggers to follow!</p> <p>Thanks for reading!</p> <hr class=\"footnotes-sep\"><section class=\"footnotes\"><ol class=\"footnotes-list\"><li id=\"fn1\" class=\"footnote-item\"><p>I haven't made content for them since 2018, but that profile shows more recent articles, including one from 2023. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p> </li> </ol> </section> ",
      "content_text": "Last night, I discovered Blaugust! I've been wanting to write more, and this seems like a great way to push myself to do exactly that. I doubt I'll write 31 posts this month ... I'm already a day or so behind. However, writing even 5 posts this month will definitely be a record for me. The suggested prompt for the first day is to introduce yourself, so that's what this is! (I guess technically my first &quot;blaugust&quot; post was about a scam call). I'm Andrew! I'm a software engineer from Toronto, Canada. For me, writing code isn't just about solving the problem. It's about understanding the domain and finding an elegant solution that, ideal, makes solving the next problem just a little bit easier. I'm passionate about the craft of writing code, and about finding good patterns and conventions that can make building tools simpler. I've had jobs as both a primarily front-end and primarily back-end developer. Right now, I consider myself to be pretty full-stack, and work on the server and client most days. But I think I'll always be a little more comfortable on the back-end. I worked in fintech for a while, but now I work in education tech. I've worked mostly in JavaScript or TypeScript environments. These days I enjoy discovering and sharing TypeScript patterns that improve developer experience. For most of my time on the internet, I've been writing or making videos about programming. Originally, I did this for Tuts+. Apparently, they're still updating and republishing some of my old articles!1 A few years back, I started making videos again, this time on my own YouTube channel. And now I'm trying to write here more often. So far, this blog has been mostly technical, it's been programming-related. However, that's not the only thing I think about. I'm a Christian, and am always learning more about what it looks like to have a deeper relationship with God, and to live out my faith. Christianity is supposed to be primarily about that relationship, and not about a lot of the other stuff that gets labeled as &quot;Christian&quot; these days. Religion has done a lot of harm to a lot of people in the name of Christianity. I'm also interested in topics like productivity and having healthy relationships. However, I think I'll stick to writing about technical stuff for now, at least publicly. I'm excited to be participating in Blaugust and look forward to discovering new bloggers to follow! Thanks for reading! I haven't made content for them since 2018, but that profile shows more recent articles, including one from 2023. ↩︎    ",
      "date_published": "2024-08-04T02:03:08.000Z",
      "tags": [
        "blaugust"
      ]
    },
    {
      "id": "https://shaky.sh/where-it-started/",
      "url": "https://shaky.sh/where-it-started/",
      "title": "Where it started",
      "content_html": "<!-- From [Loren's Blog](https://lorenblog.me/confessions-of-a-non-gamer/): > Maybe I have been a gamer, just in a different sense. My games involve experimenting with different apps and learning everything I can do with them. I love creating automations with tools like Keyboard Maestro, Hazel, Alfred, Raycast, PopClip, Apple Shortcuts, and BetterTouchTool, to name a few. Fooling around with technology is my form of gaming.  Loren is responding to Lou Plummer's [Confessions of a Non-Gamer](https://louplummer.lol/confessions-of-a-non-gamer).  There have been times&mdash;when I hear from friends and coworkers about their gaming experiences&mdash;that I wanted to get into gaming. But I never could get my self to do it. Even the few games that I have played for longer than a few minutes[^1] are all very much puzzle games. And that's where I really connect with Loren: for me, technology has always been, firstly, a puzzle I wanna solve.  [^1]: Like [Monument Valley](https://www.monumentvalleygame.com/mvpc) (which Lou mentioned), [Baba Is You](https://en.wikipedia.org/wiki/Baba_Is_You), or [Rymdkapsel](https://rymdkapsel.com/) --> <p>I can't remember a time when I didn't love puzzles.</p> <p>When people ask what, as a kid, I wanted to be when I grew up, I always say that I wanted to be Sherlock Holmes. I even asked for (and received) a magnifying class for my 8th birthday.</p> <p>But later that year, at Christmas 1998, we got our first family PC, running Windows 98. Of course, my parents also picked up several kids' games for learning math and reading; and those were fun enough. But mainly, I loved trolling through any program I could find on the PC and figuring out how it worked and what it was capable of.</p> <p>I remember one occasion, when my younger brothers were outside building a snowman, I came back inside early to figure out why, sometimes, Microsoft Word would insert new characters before existing characters and other times would overwrite the existing characters (that's when I learned about the <code>insert</code> key on a Windows keyboard). Another time, I spent hours mastering every paragraph styling option. (For a while, Word was my main source of puzzles.)</p> <p>Eventually, existing programs felt less shiny than the idea of writing my own programs, which is when I decided that I wanted to build websites, to be a programmer. And from the beginning, I knew I wanted to write the code, and not use WYSIWYG editors. Someone gave me a copy of <em>Making Websites for Dummies</em>, and I was so disappointed when most of it was about Java Applets, Dreamweaver, and other copy-and-paste embeddables. There was a single page (more like half-a-page with a large illustration) that introduced actual code: that was where I learned my first bit of HTML: <code>&lt;div&gt;</code>, <code>&lt;h1&gt;</code> and <code>&lt;hr&gt;</code>.</p> <p>But that hooked me.</p> <p>Finally, I was writing &quot;code&quot; to control this computer. From there, I got books on HTML (XHTML, actually) and JavaScript, and started learning. I found Douglas Crockford's lectures on JavaScript and watched them repeatedly, until I finally started to understand some of it.</p> <p>I even wrote him a very formal-sounding email, asking for help.</p> <blockquote> <p>April 22, 2008</p> <p>Dear Mr. Crockford,</p> <p>I'm a high school student aspiring to be a developer and I would like to learn JavaScript well. I recently saw your Action-packed JavaScript Trilogy and enjoyed it a lot (although I didn't understand all of it!). I have a basic understanding of JavaScript, have wriiten a few extremely basic scripts, and want to go deeper. Do you have a list of recommended sites, articles, etc. for a beginning scripter?</p> <p>Thank you for your time and help!</p> <p>Sincerely,</p> <p>Andrew Burgess</p> </blockquote> <p>Unsurprisingly, I never got a response.</p> <p>At some point, I moved away from the web for a while, and learned some Visual Basic. <a href=\"https://www.bobtabor.com/\">Bob Tabor</a> had a bunch of high quality free videos on one of Microsoft's developer websites. But it didn't take long for me to return to the web, and that's where I've been in one form or another ever since.</p> ",
      "content_text": " I can't remember a time when I didn't love puzzles. When people ask what, as a kid, I wanted to be when I grew up, I always say that I wanted to be Sherlock Holmes. I even asked for (and received) a magnifying class for my 8th birthday. But later that year, at Christmas 1998, we got our first family PC, running Windows 98. Of course, my parents also picked up several kids' games for learning math and reading; and those were fun enough. But mainly, I loved trolling through any program I could find on the PC and figuring out how it worked and what it was capable of. I remember one occasion, when my younger brothers were outside building a snowman, I came back inside early to figure out why, sometimes, Microsoft Word would insert new characters before existing characters and other times would overwrite the existing characters (that's when I learned about the insert key on a Windows keyboard). Another time, I spent hours mastering every paragraph styling option. (For a while, Word was my main source of puzzles.) Eventually, existing programs felt less shiny than the idea of writing my own programs, which is when I decided that I wanted to build websites, to be a programmer. And from the beginning, I knew I wanted to write the code, and not use WYSIWYG editors. Someone gave me a copy of Making Websites for Dummies, and I was so disappointed when most of it was about Java Applets, Dreamweaver, and other copy-and-paste embeddables. There was a single page (more like half-a-page with a large illustration) that introduced actual code: that was where I learned my first bit of HTML: &lt;div&gt;, &lt;h1&gt; and &lt;hr&gt;. But that hooked me. Finally, I was writing &quot;code&quot; to control this computer. From there, I got books on HTML (XHTML, actually) and JavaScript, and started learning. I found Douglas Crockford's lectures on JavaScript and watched them repeatedly, until I finally started to understand some of it. I even wrote him a very formal-sounding email, asking for help.  April 22, 2008 Dear Mr. Crockford, I'm a high school student aspiring to be a developer and I would like to learn JavaScript well. I recently saw your Action-packed JavaScript Trilogy and enjoyed it a lot (although I didn't understand all of it!). I have a basic understanding of JavaScript, have wriiten a few extremely basic scripts, and want to go deeper. Do you have a list of recommended sites, articles, etc. for a beginning scripter? Thank you for your time and help! Sincerely, Andrew Burgess  Unsurprisingly, I never got a response. At some point, I moved away from the web for a while, and learned some Visual Basic. Bob Tabor had a bunch of high quality free videos on one of Microsoft's developer websites. But it didn't take long for me to return to the web, and that's where I've been in one form or another ever since. ",
      "date_published": "2024-08-07T01:10:06.000Z",
      "tags": [
        "blaugust2024",
        "100DaysToOffload"
      ]
    }
  ]
}