<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Peter Repukat</title>
    <description>The latest articles on DEV Community by Peter Repukat (@alia5).</description>
    <link>https://dev.to/alia5</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F63157%2Fcb6373a7-cd24-42df-b634-4c1ed80cbf98.png</url>
      <title>DEV Community: Peter Repukat</title>
      <link>https://dev.to/alia5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alia5"/>
    <language>en</language>
    <item>
      <title>Supporting ancient browsers using modern Web-Tooling</title>
      <dc:creator>Peter Repukat</dc:creator>
      <pubDate>Tue, 20 Aug 2024 13:32:51 +0000</pubDate>
      <link>https://dev.to/cmdscale/supporting-ancient-browsers-using-modern-web-tooling-482k</link>
      <guid>https://dev.to/cmdscale/supporting-ancient-browsers-using-modern-web-tooling-482k</guid>
      <description>&lt;p&gt;In recent years, IE has become deprecated and Web-Developers often don't need to worry about backward-compatibility much anymore.&lt;br&gt;&lt;br&gt;
However, there are still scenarios where supporting older browsers is required, especially in industrial settings.&lt;br&gt;&lt;br&gt;
I recently encountered this challenge while developing a web-based Human-Machine Interface (HMI) for a client.&lt;br&gt;&lt;br&gt;
The requirement? Make it work with an old Qt-Embedded Browser based on Chromium 56, a browser-engine released in January 2017.&lt;/p&gt;

&lt;p&gt;Yes, you read that right – that's over seven years old!&lt;br&gt;&lt;br&gt;
This presented unique challenges, as the baseline for modern tooling doesn't account for browsers that old anymore.&lt;br&gt;&lt;br&gt;
However, with just a tiny amount of work, it's surprisingly manageable to support these ancient platforms with modern tools.&lt;/p&gt;
&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;p&gt;For those who want to skip the details, here are the key tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/vitejs/vite/tree/main/packages/plugin-legacy" rel="noopener noreferrer"&gt;Vite-Plugin-Legacy&lt;/a&gt; - For ES5 conversion and polyfilling&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/csstools/postcss-plugins/tree/main/plugin-packs/postcss-preset-env" rel="noopener noreferrer"&gt;PostCSS Preset Env&lt;/a&gt; - For using modern CSS features
- (For Ancient Browsers) Avoid using CSS-Grid, opt for Flexbox instead&lt;/li&gt;
&lt;li&gt;  (If needed) Patch dependencies with &lt;a href="https://pnpm.io/cli/patch" rel="noopener noreferrer"&gt;PNPM-Patch&lt;/a&gt; (or similar tools)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Challenges of Supporting Chromium 56
&lt;/h2&gt;

&lt;p&gt;Before we dive into solutions, let's outline the main hurdles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;ES5-only JavaScript&lt;/strong&gt;: No support for ES6+ features&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;No ES Modules&lt;/strong&gt;: The baseline for modern JavaScript tooling is not available.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Limited CSS Support&lt;/strong&gt;: Many modern CSS features are not supported&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;No BigInt&lt;/strong&gt;: The DataType, needed by a dependecy of MQTT.js, is not available.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Solution 1: Converting to ES5 and Polyfilling with Vite
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; has become pretty much the norm for modern web development, but did you know it can also help support older browsers? Enter &lt;a href="https://github.com/vitejs/vite/tree/main/packages/plugin-legacy" rel="noopener noreferrer"&gt;vite-plugin-legacy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This plugin automatically converts modern JavaScript and adds necessary polyfills based on &lt;a href="https://github.com/browserslist/browserslist" rel="noopener noreferrer"&gt;Browserlist&lt;/a&gt;-targets using &lt;a href="https://babeljs.io" rel="noopener noreferrer"&gt;Babel&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;It's extremely easy to set up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;legacy&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-legacy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;// ... your other plugins,&lt;/span&gt;
        &lt;span class="nf"&gt;legacy&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;defaults&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chrome 56&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this configuration, Vite will generate two bundles: a modern one for newer browsers and a legacy one for older browsers like Chromium 56.&lt;br&gt;&lt;br&gt;
It also includes a runtime script that loads the appropriate bundle based on the user's browser.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution 2: Enhancing CSS Support with PostCSS Preset Env
&lt;/h2&gt;

&lt;p&gt;To bring modern CSS features to older browsers, we can use &lt;a href="https://github.com/csstools/postcss-plugins/tree/main/plugin-packs/postcss-preset-env" rel="noopener noreferrer"&gt;postcss-preset-env&lt;/a&gt;. PostCSS allows you to use modern and or future CSS features and automatically adds prefixes and, most importantly, polyfills as needed.&lt;br&gt;&lt;br&gt;
If you don't know PostCSS, you probably already heard of Tailwind, right? It's just another PostCSS-Plugin ;)&lt;/p&gt;

&lt;p&gt;As Vite has support for PostCSS included, all one has to do is to install the preset-env plugin and create a &lt;code&gt;postcss.config.js&lt;/code&gt;-file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** @type {import('postcss-load-config').Config} */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;presetEnv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postcss-preset-env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nf"&gt;presetEnv&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;autoprefixer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nesting-rules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;has-pseudo-class&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;browserslist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;defaults and chrome &amp;gt;= 56&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup allows you to use many modern CSS features while ensuring compatibility with your Browserlist-targets, like Chromium 56.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotchas and Workarounds
&lt;/h2&gt;

&lt;p&gt;While the above solutions solve many issues, there are still some gotchas to be aware of:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS Grid&lt;/strong&gt;: Polyfills for CSS Grid and gap properties exist, but are not very performant or well maintained...&lt;br&gt;&lt;br&gt;
For ancient browsers, it's often better to fall back to Flexbox with margins.&lt;br&gt;&lt;br&gt;
It might not be as elegant, but it gets the job done without significant performance hits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BigInt Issues&lt;/strong&gt;: Some libraries (like MQTT.js in my case) have dependencies that use BigInt, which isn't available in older browsers. Babel doesn't provide a BigInt polyfill, so we need to get creative.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution 3: Patching Dependencies
&lt;/h2&gt;

&lt;p&gt;When all else fails, you might need to patch your dependencies. I encountered this with MQTT.js, where a dependency was using BigInt (in my case unnecessarily). Here's how I solved it using pnpm's patch feature:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Run &lt;code&gt;pnpm patch &amp;lt;package-name&amp;gt;&lt;/code&gt; to create a temporary folder with the package's source code.&lt;/li&gt;
&lt;li&gt; Edit the files in this temporary folder, replacing or removing all occurrences of BigInt.&lt;/li&gt;
&lt;li&gt; Apply the patch with &lt;code&gt;pnpm patch-commit &amp;lt;temporary-folder&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This creates a &lt;code&gt;.pnpm-patches&lt;/code&gt; folder in your project, and the patch will be automatically applied whenever you run &lt;code&gt;pnpm install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You could provide a BigInt polyfill and replace the native BigInt with it.&lt;br&gt;&lt;br&gt;
In most cases, this is probably the better solution - In my specific case however, that wasn't necessary, so I just opted to remove it.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Supporting ancient browsers doesn't mean you have to give up on modern development tools and frameworks.&lt;br&gt;&lt;br&gt;
With tools like Vite, PostCSS, and clever use of dependency patching, you can very easily develop without too much thought of platforms from yesteryear.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>browser</category>
      <category>tooling</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why Svelte is a game changer for IIoT development</title>
      <dc:creator>Peter Repukat</dc:creator>
      <pubDate>Wed, 07 Aug 2024 08:42:40 +0000</pubDate>
      <link>https://dev.to/alia5/why-svelte-is-a-game-changer-for-iiot-development-13bn</link>
      <guid>https://dev.to/alia5/why-svelte-is-a-game-changer-for-iiot-development-13bn</guid>
      <description>&lt;p&gt;Disclaimer: This was originally posted on &lt;a href="https://behind.flatspot.pictures" rel="noopener noreferrer"&gt;my own blog&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you've done any development on IIoT HMIs, you've probably spent countless hours wrestling with bulky frameworks, trying to make them play nice with old and outdated IIoT systems. Well, grab a coffee (or your beverage of choice), and let me tell you about how Svelte might just make your life a whole lot easier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tiny bundles for resource-constrained devices&lt;/li&gt;
&lt;li&gt;Lightning-fast performance with minimal overhead&lt;/li&gt;
&lt;li&gt;Sveltes small ecosystem is not a problem&lt;/li&gt;
&lt;li&gt;DX Matters: Intuitive syntax for rapid development&lt;/li&gt;
&lt;li&gt;UI-polish with "no-code"-animations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Svelte Advantage
&lt;/h2&gt;

&lt;p&gt;In recent years, I have mainly done development and consulting work on IIoT (or adjacent) projects. Modern solutions often use web-technologies for their HMIs and dashboards.&lt;br&gt;
I've used the big three Frameworks (React, Vue, Angular) with great success in that area, however, when I discovered Svelte, I was immediately impressed by its potential.&lt;br&gt;
After a few years of working with Svelte on the side, I'm, certain that Svelte could be a game-change for HMI development.&lt;br&gt;
Let's explore why:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Bundle Size
&lt;/h2&gt;

&lt;p&gt;Let's face it, when you're working with IIoT devices that have less processing power than your toaster, the size of your application matters significantly. Svelte shines in this area with its remarkably small bundle size. Unlike traditional frameworks that ship the entire library to the browser, Svelte does most of its work at compile-time, resulting in minimal runtime code.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Low Runtime Overhead
&lt;/h2&gt;

&lt;p&gt;Svelte's approach to reactivity sets it apart from other frameworks. Instead of using a virtual DOM, Svelte compiles your code to efficient vanilla JavaScript that updates the DOM directly. This results in lower runtime overhead, making Svelte applications incredibly fast and responsive.&lt;/p&gt;

&lt;p&gt;For IIoT HMIs, where real-time data updates and immediate user feedback are often critical, this efficiency can make or break a whole project.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Ecosystem Myth
&lt;/h2&gt;

&lt;p&gt;Okay, I hear you. "But what about all those shiny React components and wrappers?"&lt;br&gt;
While it's true that Svelte's ecosystem is significantly smaller than those of the big three frameworks, it actually isn't a problem at all.&lt;/p&gt;

&lt;p&gt;Svelte's simplicity allows for easy integration with vanilla JavaScript libraries, which can be a game-changer.&lt;br&gt;
How often have you wrestled with a specific library that has a wrapper for your chosen framework, but doesn't quite have the feature set your client needs? Only to choose another framework down the line and end up writing your own wrapper anyway?&lt;/p&gt;

&lt;p&gt;By leveraging vanilla JavaScript libraries directly, you not only ditch the reliance on often times questionably maintained wrappers, you're also expanding your toolkit beyond the limitations of framework-specifics.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Developer-Friendly Experience
&lt;/h2&gt;

&lt;p&gt;One of Svelte's standout features is its intuitive, easy-to-learn syntax. As someone who has worked extensively with Svelte as well as other frameworks, I can attest that its learning curve is notably gentler than other frameworks. This translates to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster development cycles&lt;/li&gt;
&lt;li&gt;Easier onboarding of new team members&lt;/li&gt;
&lt;li&gt;More maintainable code in the long run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my experience, projects that would take weeks with other frameworks can often be completed in days with Svelte, allowing for more rapid prototyping and iteration.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Built-in Transitions and Animations
&lt;/h2&gt;

&lt;p&gt;While industrial interfaces prioritize functionality, user experience remains important.&lt;br&gt;
Well crafted animations and transitions can enhance the overall UX greatly, but are often time-consuming and hard to implement well.&lt;br&gt;
Svelte provides built-in, efficient and well crafted transitions and animations, that don't require more code than specifying what elements should have them applied to.&lt;br&gt;
This makes it trivial to create smooth and intuitive interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;While my direct experience with Svelte has been primarily outside the IIoT domain, the framework's characteristics align well with the unique challenges of industrial interface development. Its small footprint, high performance, and developer-friendly nature make it a promising candidate for building modern and efficient HMIs.&lt;/p&gt;

&lt;p&gt;If you're considering upgrading your IIoT interfaces or starting a new project, Svelte is certainly worth exploring. Its potential to streamline development, enhance performance, and improve maintainability could provide significant benefits in the industrial context.&lt;/p&gt;

&lt;p&gt;As we continue to push the boundaries of what's possible in IIoT, tools like Svelte offer exciting opportunities to create more responsive, efficient, and user-friendly industrial interfaces. I'm looking forward to seeing how this technology can be leveraged to drive innovation in the IIoT space.&lt;/p&gt;

&lt;p&gt;If you're interested in discussing Svelte or IIoT development, feel free to reach out.&lt;br&gt;
If you need any of my expertise in a professional setting, you can hire me or my colleagues via my employer, &lt;a href="https://cmdscale.com" rel="noopener noreferrer"&gt;CmdScale&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>hmi</category>
      <category>iiot</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Customizing the godawul MS Teams</title>
      <dc:creator>Peter Repukat</dc:creator>
      <pubDate>Sun, 10 Apr 2022 17:45:40 +0000</pubDate>
      <link>https://dev.to/alia5/customizing-the-godawul-ms-teams-2b8i</link>
      <guid>https://dev.to/alia5/customizing-the-godawul-ms-teams-2b8i</guid>
      <description>&lt;p&gt;So, I recently got a new job, and we use Teams for communication. Instead of the way better alternatives like Slack, for example.&lt;/p&gt;

&lt;p&gt;I got fed up with how much "M$ Teams" sucks and decided to look into customizing it.&lt;/p&gt;

&lt;p&gt;The result of one weekend of hacking is a proof of concept tool which allows you to enable debugging of the Teams app and even inject Javascript/CSS (this functionality is pretty limited ATM).&lt;/p&gt;

&lt;p&gt;The whole project needs &lt;strong&gt;a lot&lt;/strong&gt; of help, currently.&lt;/p&gt;

&lt;p&gt;So, fellow developers, that suffer from having to use the super shitty Teams, &lt;strong&gt;please take a look at and hack at it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/Alia5/MS-Teams-Customize" rel="noopener noreferrer"&gt;https://github.com/Alia5/MS-Teams-Customize&lt;/a&gt;&lt;br&gt;
NPM: &lt;a href="https://www.npmjs.com/package/msteams-customizer" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/msteams-customizer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to help and have any questions, feel free to reach out via &lt;a href="https://1-3-3-7.dev/u/twitter" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>msteams</category>
      <category>electron</category>
      <category>javascript</category>
      <category>teams</category>
    </item>
    <item>
      <title>Advanced Typescript Types, explanations and Cheatsheet</title>
      <dc:creator>Peter Repukat</dc:creator>
      <pubDate>Wed, 12 Jan 2022 19:23:12 +0000</pubDate>
      <link>https://dev.to/alia5/advanced-typescript-types-explanations-and-cheatsheet-5chg</link>
      <guid>https://dev.to/alia5/advanced-typescript-types-explanations-and-cheatsheet-5chg</guid>
      <description>&lt;p&gt;Disclaimer: This was originally posted on &lt;a href="https://1-3-3-7.dev/blog/advanced-typescript-cheatsheet-pt-1/" rel="noopener noreferrer"&gt;my own blog&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This post might get updated from time to time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: &lt;a href="https://gist.github.com/Alia5/bc7f1dd772c76736c990ed6993996f22" rel="noopener noreferrer"&gt;GitHub-Gist&lt;/a&gt;&lt;br&gt;
Skip all the explanations and just see types&lt;/p&gt;



&lt;p&gt;I've grown pretty fond of Typescript in recent years.&lt;br&gt;
In particular I very much like its &lt;a href="https://github.com/microsoft/TypeScript/issues/14833" rel="noopener noreferrer"&gt;Turing-complete type system&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Typescript provides a fair share of &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html" rel="noopener noreferrer"&gt;built-in Utility-Types&lt;/a&gt;, however, I always come back copy-pasta-ing from my old code when requiring more complex util-types.&lt;br&gt;&lt;br&gt;
So here's kind of a cheat-sheet, &lt;strong&gt;with examples and explanations&lt;/strong&gt;, for some of the advanced types I've built and used within the last years.  &lt;/p&gt;

&lt;p&gt;Also, check out &lt;a href="https://github.com/andnp/SimplyTyped" rel="noopener noreferrer"&gt;SimplyTyped&lt;/a&gt; or &lt;a href="https://github.com/sindresorhus/type-fest" rel="noopener noreferrer"&gt;TypeFest&lt;/a&gt;. They contain some truly mind-boggling, but extremely useful stuff.&lt;br&gt;&lt;br&gt;
I try not to include it in every one of my projects, so there might be some duplicates.&lt;/p&gt;

&lt;p&gt;As I find it pretty hard to explain more in-depth types, let me know where you would like to see clarification.&lt;br&gt;
Also let me know if you know any other cool, usefull or mindbending stuff!&lt;/p&gt;

&lt;p&gt;So, without further ado, &lt;em&gt;Let's dive in&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Await Type
&lt;/h3&gt;

&lt;p&gt;This one is pretty straightforward.&lt;br&gt;
We use the built-in &lt;code&gt;PromiseLike&lt;/code&gt; type to check if the input really is a promise.&lt;br&gt;
If it is, use the &lt;code&gt;infer&lt;/code&gt; keyword to deduce its type-argument and recursively 'call' &lt;em&gt;Await&lt;/em&gt; again.&lt;br&gt;
If not, just return the input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Await&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;PromiseLike&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Await&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asyncFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;res&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1337&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ResolvedReturnType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Await&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;asyncFn&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?allowUnreachableCode=true&amp;amp;allowUnusedLabels=true&amp;amp;removeComments=true&amp;amp;checkJs=true&amp;amp;allowJs=true&amp;amp;target=7#code/C4TwDgpgBAgg7gQwJbADwBUB8UC8V1QQAewEAdgCYDOUACgE4D2AtklRADJIDWEqSZAGYR6UAKrYA-LEQpUEqAC58AbgCwAKE2aAxozJVgUBFRBkdAMTK5jp81AAUASmUMWbPmQCuzAEYjsHGwyCDg6JlZ2Bwd6CConXGxYqgcARgBmdIB2Jyd1LQ1QSCgAJTjGABsANwgKMuAvejJ0cGg8eGQ0esbm1tQiiEZBWzNLMkxMFSgAemmbbz8RbQ1iMEZ6IwGoNjdIviwbAmJSShpdjy5eVAQyECkoYHovaGVBBAr2fN19Qyg7MZszmUC38oiCUAy2S+hVaUAAklRzuwYDYdhEPKhuk0WpB+q0hiNzFYJlNZjZHs9NFsEUiIAAhVGI9HsTEQBrYvoDAn-YmTGZzPBvD4QIA" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Length Type
&lt;/h3&gt;

&lt;p&gt;Another simple one is the Length type.&lt;br&gt;&lt;br&gt;
You can use this for example to infer the number of parameters to a given function or (readonly) array-lengths&lt;br&gt;
There is, however, another clever use, to which we will come back later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MyFnType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NumParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Parameters&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyFnType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBDAnmYcAywB2BzGALAHgBUA+OAXjiLlBiwBMBnOAbzgBstc8AuOAS0wAzYFHRwAvnAD84vpmAA3UQG4AsAChNSFHACyiAGKYiyVJQAUAQ3kBXALYAjUQBo4jvoxhRB2NwGM7J1EASgoyW0wAa0wIAHdMdS0NHVQAOQcABSsoK3tmSgwcfAJs3PtgOihGAgNjUxQSEhU4AHpWijgAZiA" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  KeysOfType
&lt;/h3&gt;

&lt;p&gt;I find this one particularly useful from time to time.&lt;br&gt;
It returns the keys of a given interface &lt;code&gt;O&lt;/code&gt;, but only if they are of type &lt;code&gt;T&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;KeysOfType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;


&lt;span class="c1"&gt;// example &lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MyInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;keyA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;keyB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;keyC&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyInterface&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;keyD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1337&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;KeysOfTypeNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;KeysOfType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'keyA' | 'keyD'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one is not as easy to unserstand, so how does it work?&lt;br&gt;
First, we create a new type that contains all of the keys of &lt;code&gt;O&lt;/code&gt;,&lt;br&gt;
then we get the valueType of &lt;code&gt;O&lt;/code&gt; by its key &lt;code&gt;O[K]&lt;/code&gt; and then check if it is of type &lt;code&gt;T&lt;/code&gt;&lt;br&gt;
If so, we just use the key &lt;code&gt;K&lt;/code&gt; as our value, otherwise, we use &lt;code&gt;never&lt;/code&gt;.&lt;br&gt;
This would result in something like &lt;code&gt;{ keyA: 'keyA'; keyB: never }&lt;/code&gt;&lt;br&gt;
The last step now is to look up this intermediate type, by all the keys of our interface &lt;code&gt;O&lt;/code&gt;.&lt;br&gt;
The &lt;code&gt;never&lt;/code&gt; type gets discarded when looking up a type like this.&lt;br&gt;
But because of this, if we wanted to filter our interface, we cannot just leave out the lookup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus&lt;/strong&gt;: PickByType&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ConvertLiterals would convert literal types like `1337` to their base type like `number` if set to true &lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PickByType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ConvertLiterals&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;KeysOfType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;ConvertLiterals&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PickedByNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PickByType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// { keyA: number; keyD: 1337 }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBDAnmYcDSxEGcDyAzAFWWAB4cAaOAgPjgF44BvAWACg4O4BtNOASwB2cANaYIeODgC6ALkk8pcUDGACAJlipwA-OjhyBwAG7AoAbjYBfLqMTjJUi6zZsA9K6UgAhgFswAG1QXVkEVKDwvAGNUAFlEAEkBMIjopjZOEUwAQQMAVx8AI1NydM5bACE5LBgoQQBzEvYyzABhOQAlYEjoNRJq2oEGuDjE5KjgakaM2wAROQBGAGZFgHYrJzYkFHRMXEJiADl8oqh6Hex8IhQSEaTTFOBKAWPTajM4dzOAIlssr7gAD5wH6YGZfYKgSCwOBqLr+LxQVBbVBXYAtLzVEgESgAVVoDAInhU6k0OJ0WgMxlMG1Yn3KEGemjcHhaDJMsAAMnwwl5-JoAO4QXL+NRwboCdnwfzc0y8hDETTS0RwAAGS1WKoQEAQAAtgHxTgUMUjiHAlagVc9CqZNXwJFhgPAYNqarkgqxIdAnaaAAp8SLCcqIVFkSjYuCsiWmGBcnl8omqDRwAoQCCBLxCBgRPkTM4sJocHj8IQYC77a4UKjUWQRtnR2Oy+PKROaV2oXSEuQ4BTrYLIuB+gPANRBo7W04MQeB4PEG4JO7hcZPF5QN4fDyMTKIHJwK0nd6zBbLFZwSxAA" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  OneOf
&lt;/h3&gt;

&lt;p&gt;Suppose you have an Interface (or intersecting Interfaces) and you want to create a (strict) Union type from it.&lt;br&gt;
In the aforementioned &lt;em&gt;SimplyTyped&lt;/em&gt; library, there exist types with which you can do the same thing.&lt;br&gt;
I personally like this version better, though, as it's a single 'one-liner' (&lt;em&gt;cough&lt;/em&gt;) type that one can even parameterize.&lt;/p&gt;

&lt;p&gt;Let's start with just the type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OneOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Strict&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OuterKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;Strict&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;InnerKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]?:&lt;/span&gt; &lt;span class="nx"&gt;InnerKey&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;TheKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now break this down somewhat.&lt;br&gt;
First, we omit the second type parameter &lt;code&gt;Strict&lt;/code&gt; and only use the then false-case and just look at a simpler &lt;code&gt;Unionize&lt;/code&gt; type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Unionize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OuterKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a type with the keys of the input type &lt;code&gt;T&lt;/code&gt; as key and a new dictionary type containing a single &lt;code&gt;key-of T&lt;/code&gt; and the corresponding &lt;code&gt;value type of T&lt;/code&gt; as value.&lt;br&gt;
Afterward, we use the look-up trick we already used above to get a union type of the inner dictionary types (hence the unionize name)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MyIface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;keyA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;keyB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Demo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Unionize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyIface&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = { keyA: number } | { keyB: string }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Unionize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyIface&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;keyA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1337&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// ok&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Unionize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyIface&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;keyA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1337&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;keyB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// also okay&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because union dictionary types are not exclusive.&lt;br&gt;
In some cases, it can be okay, other times you'd want it to be strict.&lt;br&gt;
So let's look at that&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OneOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OuterKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;InnerKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]?:&lt;/span&gt; &lt;span class="nx"&gt;InnerKey&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;TheKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;TheKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this is a bit more complex.&lt;br&gt;
If we look closely, however, it is the same as the &lt;code&gt;Unionize&lt;/code&gt; type shown above &lt;strong&gt;except for&lt;/strong&gt; an intersecting type: &lt;code&gt;{ [InnerKey in OuterKey|keyof T]?: InnerKey extends OuterKey ? T[OuterKey] : never }&lt;/code&gt;.&lt;br&gt;
Let's break this down some more.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OuterKey&lt;/code&gt; is a single key of our input-type &lt;code&gt;T&lt;/code&gt;. Create a union with that and with all &lt;code&gt;keys of T&lt;/code&gt; as keys for the inner dictionary (&lt;code&gt;[InnerKey in OuterKey|keyof T]: ...&lt;/code&gt;).&lt;br&gt;
For the value of the inner dictionary, we check if the current &lt;code&gt;InnerKey&lt;/code&gt; is the &lt;code&gt;OuterKey&lt;/code&gt; (&lt;code&gt;InnerKey extends OuterKey ...&lt;/code&gt;).&lt;br&gt;
If it is, we use the value-type of our original type &lt;code&gt;T&lt;/code&gt;, otherwise &lt;code&gt;never&lt;/code&gt;.&lt;br&gt;
The last part is to make every key for this dictionary optional (the &lt;code&gt;?&lt;/code&gt; after the key declaration).&lt;/p&gt;

&lt;p&gt;Now this gives us a type which, has &lt;em&gt;all keys of the input-type&lt;/em&gt;, but &lt;strong&gt;only a single key&lt;/strong&gt; is allowed to be assigned with a value-type &lt;strong&gt;other than undefined&lt;/strong&gt;.&lt;br&gt;
That means we can still use &lt;code&gt;undefined&lt;/code&gt;, though.&lt;br&gt;
We can still use undefined, though.&lt;br&gt;
To mitigate this, we add an intersection to an inner dictionary, that being the one we've seen in the &lt;code&gt;Unionize&lt;/code&gt; type, as it doesn't allow undefined.&lt;/p&gt;

&lt;p&gt;The result is the something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OneOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Strict&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OuterKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;Strict&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;InnerKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]?:&lt;/span&gt; &lt;span class="nx"&gt;InnerKey&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;TheKey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;OuterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;TheKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;


&lt;span class="c1"&gt;// example&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MyInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;keyA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;keyB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;keyC&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;keyD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1337&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OnlyOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;OneOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyInterface&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ^= more or less strict version of { keyA: number } | { keyB: string } | { keyC: Record&amp;lt;string, MyInterface&amp;gt; } | { keyD: 1337 }&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NonStrictVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;OneOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// { keyA: number } | { keyB: string } | { keyC: Record&amp;lt;string, MyInterface&amp;gt; } | { keyD: 1337 }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBDAnmYcDyA7YaBmAeAFQBo4BlGKASwGN5QZgMATAZzgCMIIAbYAQwxwAvAigBXYAD5hcAN4BYAFBwVcANpoxDKAGlgiOJUEBrfRBxwCAXQBcZCjTogGzNjj7cWqAPxz1Ow0FNbT1EW0s1HSs4AF84O1l1AEkMLF19QPQtYHTEAB9TRHNLK287FLTQuHpGViyQjN8CDWzc6LssADcc2LgAMj81AgALYCqjepzQ8Obgqf1ouKUYtULi6wBuJSUAeh3qkD4AWzBeJSNtd2pUAFlEFMu+a7klVThCgEEOsSP2HKJXqpCgAhOwsBwYADmAOUQP0AGE7AAlYDUaBMPDgqhQkhiDDGDAQADuGEkMLehQAInYAIwAZjpAHZlltFEokCh0BhuIhMKgRHzcHg7g8clcpBs4Hs4AA9ERHaCoaBwXgsNhYxxwbpQFiUCCCYqJT7fX49OJ5PwgsEQyG9C1GhHI1HozE2kgijCPa7Sc2W-TUuD0pmxdnIVAAOX15CotAAajldfqZIL8B6vcASO5PBKpfsHYgvnAMD8-lA7X7EKC4BqoeX84i4Ci0VAMTXoXA02KnlI6+9-bSGYyQ2yR2iMOC4Hw7CnhfdPV3vTIFLCVMbA4OWdtR-qJ8AadOsELO1BxdIRMuKfpC3imMAcEZgExN9vx3QAEwH7Cpufps8vFeTuw1C0jCMSskoY67nSn5Hj+C49uegKrleIFIX2lZ2AA5ISKCYc+EE7vAEDGHwiAAPpGGRhKvjGMAwd+oont2mYeF4f4XnCBaoQBVpwNhEC4fhiiQXQACs9Gzoxp5Lmha40uSnFVm+QkidUABsEnHtJiE8ShgYKchGF8TSb50phBnoQ2iTsNwU5yHEMQWVSA5Ms+QA" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tuple Manipulation
&lt;/h2&gt;

&lt;p&gt;Tuples, combined with the ability to spread them and infer single or even rest-types, are an incredibly useful tool when dealing with more complex types.&lt;br&gt;
So here are a few basic manipulation types starting with:&lt;/p&gt;
&lt;h3&gt;
  
  
  Push, PushFront, Pop, PopFront, Shift, ShiftRight
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Push&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PushFront&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Pop&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PopFront&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Shift&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ShiftRight&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These should all be pretty straightforward.&lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; You could just as well use any instead of infer X where X isn't used.&lt;/p&gt;
&lt;h3&gt;
  
  
  Reverse
&lt;/h3&gt;

&lt;p&gt;Since there are no loop-functions for TypeScripts type-system, and we somehow need to iterate over the input tuple, we have to use recursion.&lt;br&gt;
To check when the recursion needs to end, we can use the aforementioned &lt;code&gt;Length&lt;/code&gt;-type. Afterward, just Pop from one tuple, and Push to another.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Reverse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Push&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Pop&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Reverse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ShiftRight&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Push&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Pop&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A little bit special here is the second type-parameter, which is default initialized to an empty tuple.&lt;br&gt;
We basically use that as our return value, after recursively filling it from the input &lt;code&gt;T&lt;/code&gt;.&lt;br&gt;
If you wanted to restrict any other devs in your codebase to do nasty things with the second type parameter, you can just wrap the above implementation.&lt;/p&gt;
&lt;h3&gt;
  
  
  Filter, TupleIncludes
&lt;/h3&gt;

&lt;p&gt;Next, let's look at a filter-type. This one's also pretty simple.&lt;br&gt;
First, check if our tuple is empty. If it's not, infer the first Element &lt;code&gt;F&lt;/code&gt; and the rest of the tuple as another type &lt;code&gt;R&lt;/code&gt;.&lt;br&gt;
Then we check if &lt;code&gt;F&lt;/code&gt; is equal to, or extends, the type we want to filter out.&lt;br&gt;
If it is, return &lt;em&gt;Filter&lt;/em&gt; again, but this time on the rest &lt;code&gt;R&lt;/code&gt; without &lt;code&gt;F&lt;/code&gt;.&lt;br&gt;
Otherwise, we return a new tuple, with &lt;code&gt;F&lt;/code&gt; at the front and a spread (...) of the filtered-rest.&lt;/p&gt;

&lt;p&gt;Combining the &lt;code&gt;Filter&lt;/code&gt; type with our handy-dandy &lt;code&gt;Length&lt;/code&gt;-type, we can also build an Includes-type by simply comparing the lengths of the filtered and unfiltered tuple!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;F&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TupleIncludes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?#code/PTAyFMDsHMBcAsAEsCeAHciDumCGAbAJ3FwBMVEBrSAeywChwAPNGw2ZdTCGBAHgAqAPkQBeRAMTNYUUgGdEAb0T4oceAC5EAS0gAzcIUShEAX0QB+Y4i2RwAN0MBuevRCIARrjnaAxogBXWG18OXpUDEQABQC5eEEpJhlIeUDIajpIAG0AXQAaRABVEXFJaVkFLIA6Gt0DIwAlHMtEapqBAsLm2wdncK5o2PgAMUIaSFgE8pSFAPTaLGz8opKJROTUtqq6w0QmlqzCgpqqgW7EO0dCFwjMKJo0KaSKtIzF3NWy55nWk53Ggr-IrNKyFGwXXrXfqRe5oUbjSZfDazeaZD5iNbTTZAo6IP76Xb7UHgy59W6IADK8G0ekR6xeczeS0+9J+WRxx1qBMaIL2JMhNwGVJpsAa2mg8DpWJRTPRpVZm3x9T2gO5wJaDX5VxcbmAiAAtmw8KR7LhIL5wKRAsFQtDMA1IXJwE9ka8FktOgqZe7chi5cY1PxhF7EABGFoxOJ8XGwwRCERaB1XJ18YW0sUSxFCAqR+Ixh5x+OucnDEIyQguhmo97LYoYpEvX1WX1aBtsoHDTnbNVExDDENgqyl-DlvgNToJ1qdvE1Yej8crc6kwh2iQBNCqACS5vwAVI4DklZ+jJ9tdWPHUfDnhkEE5E0oDvHiwasegITvBsEIAXArncABEAFEAFkAHlV3-cBDVzDFcz4LIAHJcAQ5ZEI8FChCcRB3HERDkIKBD0JyCCoJoXN4QmWChgoyY8JQgo0IwrCcNaQiEII5DiPJSDoIeWCCzogiiMw7C9XENiSN4uExko8RYRo+CkPYxA2JyESWKUySaDTDhxB0xT8JU4TmLE1iiK0nSM0lDFLPFSUDOU1T1NMujiK0pNDA-cQPMIFNBKMxzfCY0S-QQoKhMczjiwGHiaGvIxxHihyIoIoLljY5zQsMsKUK07dfF3fc5AABnrdctx3PcD2SgLUvogKRBYr8fzyyqivDUpyvAfLCuq-y2Lq9LSAQxrTLfUJf3oIA" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You may have noticed that I didn't actually call the &lt;em&gt;Includes&lt;/em&gt;-type like that, but rather &lt;em&gt;TupleIncludes&lt;/em&gt;.&lt;br&gt;
We'll come back to that just below...&lt;/p&gt;
&lt;h2&gt;
  
  
  Template Literal Types
&lt;/h2&gt;

&lt;p&gt;My favorite "subtype" of Types.&lt;br&gt;
Introduced in &lt;a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html" rel="noopener noreferrer"&gt;TypeScript 4.1&lt;/a&gt;, they really filled a gap for me.&lt;br&gt;
With them, you can do &lt;a href="https://github.com/ghoullier/awesome-template-literal-types" rel="noopener noreferrer"&gt;so much fancy and mindblowing stuff&lt;/a&gt;&lt;br&gt;
Someone even wrote &lt;a href="https://twitter.com/anuraghazru/status/1310634306092462080" rel="noopener noreferrer"&gt;a full-blown CSS-Parser&lt;/a&gt; 🤯!&lt;/p&gt;

&lt;p&gt;Fancyness aside, I also want to share a few types I've found useful to me.&lt;/p&gt;
&lt;h3&gt;
  
  
  StringIncludes
&lt;/h3&gt;

&lt;p&gt;The nice part about template literals is that you can infer literal types from them.&lt;br&gt;
Even nicer: You can infer empty strings!&lt;br&gt;
Which makes a type that can check if any string includes another pretty trivial.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;StringIncludes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;D&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;D&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Demo1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StringIncludes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a.b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = true&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Demo2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StringIncludes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ab&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = false&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Demo3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StringIncludes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = true&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Demo4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StringIncludes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we now also have a &lt;code&gt;StringIncludes&lt;/code&gt; type, we can now combine that with the &lt;code&gt;TupleIncludes&lt;/code&gt; from above, to get a &lt;em&gt;completely generic&lt;/em&gt; &lt;code&gt;Includes&lt;/code&gt; type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Includes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;TupleIncludes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;StringIncludes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Template literal types are (or were, at the time of initially writing most of this), however, for some reason, more restricted than tuples, so we need to build a few types to help with that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Split
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;D&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;D&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;D&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may wonder why the first conditional is &lt;code&gt;string extends S&lt;/code&gt;.&lt;br&gt;
If you haven't guessed, it's the check if &lt;code&gt;string&lt;/code&gt; itself is passed as a type argument, instead of any literal.&lt;br&gt;
Any literal string extends string - but string doesn't extend any literal string&lt;/p&gt;

&lt;p&gt;Here's some code to better explain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Demo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;used string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`used literal: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;D1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Demo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;str&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = 'used literal: str'&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;D2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Demo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = 'used string'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Join
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;D&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;PopFront&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PopFront&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PopFront&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;D&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Shift&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;D&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using what we've learned so far and some of the tuple manipulation types above, we can now join any string tuple back to a string.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?#code/PTAEFcBcEsBsGcBQkCeAHApqAMhgdgOaQAWAPACoB8oAvKOaBgB6T4Am8oA3qLPkcQBcoaHgBmGAE45QAX1AB+GcLwYAblIDciZOiwAFAPZoAYpMN5IFRi3adweANZ5DAdzwBtALrU6DZqx4HKAeohLSAKoANKAAdPFhUqAASl6KoBGgKupaupigAMrE0GJW-rZB9k4u7t6+9DaBwaHiSdFxCa3SqenJWaCqGpLaiCCgqJhIE1gFaLDQVgWNdqDwkJKiBDEAIsuVq+ubvoigpwcbhHvBS0prFwTeWSdnL0sBKwDkH+mPgs8vAMKV04AAMACRcRLSciyCHbWGQroZWQg9IhcgxeKxWbzKztbaUNLCDwFLwjaagABShlE1ne+wczjcni8O2B5yOtA5hEe9OCDFuh0uwnKTU4d023meSiMpnMlgo1D54qFBHSuEIJEV7IAjOlwVxZWYLGVKCj+gajfLTQj4RDqbSiiVTTszajskNnh7cqMwNsMABbQw6Cn+oM4hYABi5EasEsIMQ+sQ+lE0oDGdHjDzJeSwYcMsb1dFjpA+AENYgAjD6J5Op9NgOgecs10Afas50OBgtzBYAJhjvas5ertZTaYzIRHHxzudA+YdeGjdEXpHzscjic044bXKzc4XNLwRapR7X3cLW53k4ARGXNJWbwfu4uByuz+uh32r-Xb2XHzoiBAA" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example using all of this
&lt;/h2&gt;

&lt;p&gt;A cool and really useful example, using most of the above util-types, is dealing with "Paths" and nested-types of dictionaries.&lt;/p&gt;

&lt;p&gt;(Explanations for those are left as an excersice for the reader)&lt;/p&gt;

&lt;p&gt;Let's start with valid Paths&lt;/p&gt;

&lt;h3&gt;
  
  
  ValidPaths, ValidPathTuples
&lt;/h3&gt;

&lt;p&gt;At the time of initially writing this, the Tuple version was the only one working.In most recent TS versions both work, however, the string literal version has got some gotchas and so the tuple version is somewhat preferred.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;someProp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;nested&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;moreProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;333&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;deeper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;evenDeeper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;deepest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;alsoDeeper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;randomProp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;anotherProp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wtf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MyDict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// If you look at type "Debug" below, this surprisingly works.&lt;/span&gt;
&lt;span class="c1"&gt;// You may get a `Type instantiation is excessively deep and possibly infinite.`-error if you're using an older TS version, though&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ValidPaths&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ValidPaths&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
       &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt;
   &lt;span class="p"&gt;})[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Debug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ValidPaths&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// With Tuples.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ValidPathTuples&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;ValidPathTuples&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;})[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DebugTuples&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ValidPathTuples&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// on recent TS versions you can even join the tuples back to "PathStrings"&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DebugTuples1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ValidPathTuples&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
&lt;a href="https://www.typescriptlang.org/play?#code/MYewdgzgLgBAJgS2FB4CGAnAnjAvDAbwCgYYIQBbAUwAUMQAHALhgEYAmAZgBoSYwq0KnBbFSpCiAy16DCC06Le4+FSoMqGUXxVUAblTAARNRq2EdK1esFQWAcmgYEYAOb3LpAL6Wvy8WgANuQmNuZiVhhoYHCUdIzaVgFgIFAAFprxzDD2AO5QAGYeST4qpTA+XjBoEDCgkFAA3EREUFgaMACyWEZIsPhtGiAF8H2oYJhYzURUAB4MUrCDVDAAMoau6QA8ACoAfHgwOzBzUIZwtQQwgRvpLC4FmmsVMAD8zywCBhjNyzAAUiAXLsTrMzjFagBXMAAaxSuTAAG0ALrcGBGUHgi5kKDONwHfDHU7nWpOFyuFFvGA0RgAMXoYCguwOxIhOLxrip6zc232mJJbCpAAMACQEGkMengJn7LxCmAsUXiukMmV7LxiowagiA4EAZTSCAKarRRnV8s++ielu+jRgrXaKwlUsZINZ2OhcJACJRBKO-LZiIeTwAqmiAHSR4MYGAAJWRVJDCv4Vp+Do6BqNMoDHth8KRyL9RLBAqDYEeMbDMEj4ejcYT71jya+mmmAHo2zAAJIjLAgSHXEAgGHVJaOmAAIhMACNIa4JzBp1RAt60ekEKTIRgGM4IOTAjhclIYRBw0QOzAAJr9mAUNA4VxUWBoGBCnbjlzQaIoNAocAwDdQWAQQ9wMA9rAYaoYhgBYID3adwIeFwEDOcMhQAWk0egYyNGA+0hexpBgSE9zcKCYBAQI4CeHY9Rgb493ANc0n7Vw0nTFYADUggQOAaF-NIIGZQ4YSoPsRmLLFahbGN3hk5MAAoInEREAGkALAGBRPEo5kRYHY1ITd1pNTKl5P0wyc1qWMqFADA4C2Mk3AAHzASEKCXDBnIgLAPMotFPXzPZPFId51OM9lyWFMVVK8cMxW4wJeP49IhIM1TCzlGBnJgdSbU0ELk1UnQvAASkRbThl0mAADJIrcaY-hnOdDkS5KBKE7pemQPZ207AB1FC0iOSEGBuU8OJgNq+IEnZRvG4T8EqiSrJTb4zNMlglM8NSNK0sSqp2PSjksiL5LkzaToy1abLshynNcVz3M87zfOnfziLzb0wGCpIqTUiNI2mlK0jmsbBF2Qy9gTHLDMKlg4fEMqKoOiTkUa8dmtcMHxtaniZvSHGIa6vpepaC9-2kYDGSOOiGPGWp8LqaITgMTSACsgU09IVigebBEXNBgBHKAQEnEG9VxckIAnSasaJiBWEOXUwC2YHZv5zqelJtF7HDexeqAA" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  NestedType, NestedTypeByTuple
&lt;/h3&gt;

&lt;p&gt;We can also craft a type that gets us the nested-type of a dictionary for any valid path, or throw an error if an invalid path is passed.&lt;br&gt;
And of course we can put it all together in a beautiful function where only valid Paths are allowed as parameter and the return type is automagically deduced for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// string version&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NestedType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;Includes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;PopFront&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;NestedType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PopFront&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Shift&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DemoNested1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NestedType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nested.moreProps&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 333&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DemoNested2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NestedType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nested.deeper.evenDeeper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// { readonly deepest: "string" }&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DemoNestedNever&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NestedType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nested.randomProp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// never&lt;/span&gt;

&lt;span class="c1"&gt;// tuple version&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NestedTypeByTuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Pop&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Pop&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PopFront&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Shift&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; 
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;NestedTypeByTuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PopFront&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;Shift&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DemoNestedTuple1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NestedTypeByTuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nested&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moreProps&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 333&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DemoNestedTuple2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NestedTypeByTuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nested&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deeper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;evenDeeper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// { readonly deepest: "string" }&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DemoNestedTupleNever&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NestedTypeByTuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nested&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sillyProp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// never&lt;/span&gt;

&lt;span class="c1"&gt;// String version internally using tuples&lt;/span&gt;
&lt;span class="c1"&gt;// Bonus: Also errors now&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NestedTypeUsingTuplesAgain&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;ValidPaths&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NestedTypeByTuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Convoluted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NestedTypeUsingTuplesAgain&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nested.alsoDeeper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ConvolutedError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NestedTypeUsingTuplesAgain&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyDict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nested.nonExistant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// And now we can finally give lodash's `get` function a run for it's money&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GetByPath&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;ValidPaths&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;NestedType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c1"&gt;// internal impl. must be different. only demoing types here!&lt;/span&gt;
 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dict&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?#code/MYewdgzgLgBAJgS2FB4CGAnAnjAvDAbwCgYYIQBbAUwAUMQAHALhgEYAmAZgBoSYwq0KnBbFSpCiAy16DCC06Le4+FSoMqGUXxVUAblTAARNRq2EdK1esFQWAcmgYEYAOb3LpAL6Wvy8WgANuQmNuZiVhhoYHCUdIzaVgFgIFAAFprxzDD2AO5QAGYeST4qpTA+XjBoEDCgkFAA3EREUFgaMACyWEZIsPhtGiAF8H2oYJhYzURUAB4MUrCDVDAAMoau6QA8ACoAfHgwOzBzUIZwtQQwgRvpLC4FmmsVMAD8zywCBhjNyzAAUiAXLsTrMzjFagBXMAAaxSuTAAG0ALrcGBGUHgi5kKDONwHfDHU7nWpOFyuFFvGA0RgAMXoYCguwOxIhOLxrip6zc232mJJbCpAAMACQEGkMengJn7LxCmAsUXiukMmV7LxiowagiA4EAZTSCAKarRRnV8s++ielu+jRgrXaKwlINZ2OhcJACJRBKO-LZiIAdEGHk8AEpokMYGAAVWRVOjCv4Vp+Do6EqljJdYIF7vhSORPqJ2f9kZjaKDAdLobj7wTNs0v0dMANRplfrdsLz3sORaxtURpej5eDYEeUerVNDia+DZaf1pCECZwwWb7MFznvzaOjhfb-ZrMEpLF7AoHo6etOHlfP44PtL3MapC6Xmi24aOBxYiMvMArz+Xb7bnscb1hgqYrDskIMDcACSYDAIEkJwIIq45p2m4okBhzcpsaRbP+r47EBLLFtiOG8gc7wFEEEArCwuKQlQ4HNri5JwQhSEoXqD5km4po8ax+KHNxrq1EqpY7NqWpioOcpUgxdEwNRwRUHazHsYhyEQKhbIbl6yIAD68a4WGEg+en5lSkHQVQGmcdpRExp+vqiey5LxgJHJUnqgmuHZWm7FhoHTsmLRzAsGBLE2erQQgTIiaRpK+fxrnGQSljGQ+3HvMZR6eOICVrvY9hUnlSRJIVAriTeRxSdqsnyu8h6ORWMWBHFWxDuiwGJoierItMzEAGpBAgcA0Gg6QOT6MJUFgwwuYlSbfFSM5RiwAAUETiIiADSMAuDAs3zSMOzIsee1xq5a2rcmiY7JdD6hlQoAYHAWzGQZYCQhQABGmhGVgf0gIEaIWXs+VUvtqW+cKYq7V4AZiiN7XjZNaQOZd5owAZMD7aBkMsLtOheAAlIix0LWdMAAGRuW40x-CjY0Tek1k3NNhyU6dD43e8N2bdtpB7QdYBHXNVPnUcj3XXd-N3Rdu1XUtz2ve9n3fX9AMQEDv0g2D6EIhD5XvHtV7M2jbNQRzuxY3GuOXYTh5KyT5Pc0cA0tEQAD03v05y3wQOMzEAHK2MIOyOoF1KeeSPobXw-koTQaL2AG9gkWuCmWO86aqlsbUdSnOTp3smcCu7Oz5e8YdCHAkcaLbefSgXsVMsXacZ8BaK6mABeGsarfte3qel3so9d-lBMqCwNAPpXVmIjQIHLZoRCk4zTYmJItdnHArCHLvEdR90vTIGiABEAh1wGkjSFkEAX3sdq+zAiicMx28gEfcDsIf4f1xPj0Pol9r57wDMhMIAYrTGFMJoJ+L8-ZXGkGgWIYBAg4EgRoaALAL7GQvhUT+VAd4ALDitfAP8G5UC2KfEBMAr4AIDFEGIcRZAIJgK-NaLRX5QGtisQOwc-iUMdAAISwOzahjk54ww5N2fACdSDkTwjQcubJWA52pIwLYKj54Sx5u8B6zoVEry4TPTRkp846Ncgvd4LZB5WKWrlOM1cYDCI0GIiRTcVQt2MWiOx7cy5T1XutYJ69N4dC-pQvhB8KEAKoR4vhNDgHn0PAwuuBDuAXzvjIRgj8CyILfooIhJC64SL-rE0pojxGJNoSkxEaS94ZPoVg+Bl8YGhDMBffJHCkEwBQWgjB1hsF2HofgwhfxIlxL4WQp4FS97xOqTZJJZ8oBonqWA4QF9L5B0CBgrIXTn49NCT7P2PkvICPAKLZcExdk4EhEHNwMBeE2QgCcmAIjwD3JYAAQWCCAE4GB6AYFqPCUOcTHTRgea4CREBvmuDQMCKRD4LaswxsyH0biqAJKWY5QuI8S5d3CSsAAwuAPQINIR73-pUjQkLyQwrhQivutTVk5A2XAAMNEQAdM0BnRsHRSVgHJYhPeABRQFUhqXzIhVChl8LgQstTuygMKQwCitmAgaA0QoB8u4X7b5MR+CehgLkFYwBohKRcEEQZrgEAGGuCAOANQ0iOBgEKVwVAoDygKNCZA4xqh9OhEpSVcVXWSAEFgIgPr4IoEuQAcU9WI1F0dpFLRRejaaewNqIGQMeNEDB0az1JiwTFKaDhiFfi4a5QQDoUGggGGAFB7mwH+qMAoY5DBQAbeAQZsQKAuDSJyZYtQMjSAAIQkGkLwjAYts19GqLUaIWByYFvSJ7HwRB6jQFUJIVgKNGKHATVAJN6M51+vQNgUBjDskPwvhvYpIBWBUMOMsBayFd37tUkc9+LQt2wHfSAdgn7D2JqwKis9saJiXvocqrlPKMBMOiH2rInKUjpEyGw+9EziGAefQMR0b6cNAaCIxAp+QChez-TuwD4qgUgePWB09ObIOTEvgAK2bQGcg1AuOLgwVx3h7a73TCAA" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>cheatsheet</category>
      <category>advancedtypes</category>
      <category>intermediate</category>
    </item>
    <item>
      <title>Overlay WindowsStore-Apps (UWP) without code-signing</title>
      <dc:creator>Peter Repukat</dc:creator>
      <pubDate>Thu, 06 Jan 2022 19:31:05 +0000</pubDate>
      <link>https://dev.to/alia5/overlay-windowsstore-apps-uwp-without-code-signing-2h89</link>
      <guid>https://dev.to/alia5/overlay-windowsstore-apps-uwp-without-code-signing-2h89</guid>
      <description>&lt;p&gt;Disclaimer: This post was originally posted on &lt;a href="https://behind.flatspot.pictures/overlay-uwp-apps-without-code-signing/" rel="noopener noreferrer"&gt;my own blog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I came to discover that, you cannot simply overlay Metro/UWP/Windows-Store Apps (or whatever they are called these days) using always on top windows.&lt;br&gt;&lt;br&gt;
I learned while it is possible, for that to work the program has to have the &lt;code&gt;uiAccess=True&lt;/code&gt;-flag set in the manifest, and it must be signed. &lt;br&gt;
That, of course, isn't good news for any hobby or small open-source project, as code-signing certificates cost money. &lt;br&gt;
There is another way, however...&lt;/p&gt;

&lt;p&gt;But first, let's see what happens if you try to focus any old “always on top”-window while running a fullscreen store app. &lt;br&gt;
If that happens, it causes the Windows Store app in “fullscreen”-mode to instantly minimize. &lt;br&gt;
Even though store apps never really run in exclusive fullscreen!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbehind.flatspot.pictures%2Fcontent%2Fimages%2F2022%2F01%2Fezgif-2-78f66c6af6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbehind.flatspot.pictures%2Fcontent%2Fimages%2F2022%2F01%2Fezgif-2-78f66c6af6.gif" alt="Store app minimizing when always on top Terminal gets focused"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some programs however are perfectly capable of doing this, like the Windows Taskbar itself or DisplayFusions intermediate loading window...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbehind.flatspot.pictures%2Fcontent%2Fimages%2F2022%2F01%2Fezgif-2-94f77eb287.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbehind.flatspot.pictures%2Fcontent%2Fimages%2F2022%2F01%2Fezgif-2-94f77eb287.gif" alt="DisplayFusion loading window perfectly overlaying store app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I asked the developers of DisplayFusion how they are doing it, and they shared the secret with me: The aforementioned &lt;code&gt;uiAccess=True&lt;/code&gt;-flag along with a signed executable.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://behind.flatspot.pictures/third-party-steam-controller-software-part2-my-take-on-it/" rel="noopener noreferrer"&gt;my endless quest&lt;/a&gt; in getting &lt;a href="https://alia5.github.io/GlosSI/" rel="noopener noreferrer"&gt;Steam Input to work with stuff it normally doesn't&lt;/a&gt;, an overlay for Windows Store apps would be a real boon.&lt;br&gt;
But spending ~100 bucks per year for a free project, that I have way too little time to properly maintain and support, doesn't seem all too appealing.&lt;/p&gt;

&lt;p&gt;Luckily, with a bit of hacking, using undocumented Windows APIs, I managed to get it to work.&lt;br&gt;
I think the whole process is rather interesting, and so I wanted to share it with you.&lt;/p&gt;
&lt;h2&gt;
  
  
  Window z-order
&lt;/h2&gt;

&lt;p&gt;Z-ordering in Windows 10 (up from Win8) works in so-called &lt;em&gt;“WindowBands”&lt;/em&gt;&lt;br&gt;
The order of (some) bands, from lowest to highest, is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ZBID_DESKTOP&lt;/li&gt;
&lt;li&gt;ZBID_IMMERSIVE_BACKGROUND&lt;/li&gt;
&lt;li&gt;ZBID_IMMERSIVE_APPCHROME&lt;/li&gt;
&lt;li&gt;ZBID_IMMERSIVE_MOGO&lt;/li&gt;
&lt;li&gt;ZBID_IMMERSIVE_INACTIVEMOBODY&lt;/li&gt;
&lt;li&gt;ZBID_IMMERSIVE_NOTIFICATION&lt;/li&gt;
&lt;li&gt;ZBID_IMMERSIVE_EDGY&lt;/li&gt;
&lt;li&gt;ZBID_SYSTEM_TOOLS&lt;/li&gt;
&lt;li&gt;ZBID_LOCK (Win10)&lt;/li&gt;
&lt;li&gt;ZBID_ABOVELOCK_UX (Win10)&lt;/li&gt;
&lt;li&gt;ZBID_IMMERSIVE_IHM&lt;/li&gt;
&lt;li&gt;ZBID_GENUINE_WINDOWS&lt;/li&gt;
&lt;li&gt;ZBID_UIACCESS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbehind.flatspot.pictures%2Fcontent%2Fimages%2F2022%2F01%2F2022-01-05_1200.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbehind.flatspot.pictures%2Fcontent%2Fimages%2F2022%2F01%2F2022-01-05_1200.png" alt="Multiple windows, annotated with WindowBands"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're wondering why you never heard of “WindowBands” before, it is because you normally won't get to use them (explicitly).&lt;br&gt;
All the APIs are undocumented and not made publicly available by Microsoft.&lt;br&gt;
But we will get to that. &lt;/p&gt;

&lt;p&gt;Any regular old window gets created with &lt;code&gt;ZBID_DESKTOP&lt;/code&gt; and will remain there.&lt;br&gt;
Setting a window to be always-on-top using &lt;code&gt;SetWindowPos(...)&lt;/code&gt; will just change the ordering inside the &lt;code&gt;ZBID_DESKTOP&lt;/code&gt;-band. &lt;br&gt;
An expectation to that is, for example, the previously mentioned &lt;code&gt;uiAccess=True&lt;/code&gt;-flag&lt;br&gt;
with a signed executable. Then the window will get created in the &lt;code&gt;ZBID_UIACCESS&lt;/code&gt;&lt;br&gt;
-band.&lt;/p&gt;

&lt;p&gt;If any &lt;code&gt;ZBID_DESKTOP&lt;/code&gt;-window gets “touched” while running a store app in “fullscreen”-mode, the store app gets minimized.&lt;br&gt;
Other bands don't necessarily cause that behavior. &lt;/p&gt;
&lt;h2&gt;
  
  
  Using other WindowBands
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Enum&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;ZBID&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_DEFAULT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_DESKTOP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_UIACCESS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_IHM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_NOTIFICATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_APPCHROME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_MOGO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_EDGY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_INACTIVEMOBODY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_INACTIVEDOCK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_ACTIVEMOBODY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_ACTIVEDOCK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_BACKGROUND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_SEARCH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_GENUINE_WINDOWS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_IMMERSIVE_RESTRICTED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_SYSTEM_TOOLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// Win10&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_LOCK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ZBID_ABOVELOCK_UX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CreateWindowInBand&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Same as &lt;code&gt;CreateWindowEx&lt;/code&gt; except with 1 more parameter &lt;code&gt;dwBand&lt;/code&gt; where you specify the band the window should stay.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;HWND&lt;/span&gt; &lt;span class="n"&gt;WINAPI&lt;/span&gt; &lt;span class="nf"&gt;CreateWindowInBand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="n"&gt;DWORD&lt;/span&gt; &lt;span class="n"&gt;dwExStyle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;LPCWSTR&lt;/span&gt; &lt;span class="n"&gt;lpClassName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;LPCWSTR&lt;/span&gt; &lt;span class="n"&gt;lpWindowName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;DWORD&lt;/span&gt; &lt;span class="n"&gt;dwStyle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;nWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;nHeight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;HWND&lt;/span&gt; &lt;span class="n"&gt;hWndParent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;HMENU&lt;/span&gt; &lt;span class="n"&gt;hMenu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;HINSTANCE&lt;/span&gt; &lt;span class="n"&gt;hInstance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;LPVOID&lt;/span&gt; &lt;span class="n"&gt;lpParam&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;DWORD&lt;/span&gt; &lt;span class="n"&gt;dwBand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;SetWindowBand&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Same as &lt;code&gt;SetWindowPos&lt;/code&gt; except with 1 more parameter &lt;code&gt;dwBand&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;BOOL&lt;/span&gt; &lt;span class="n"&gt;WINAPI&lt;/span&gt; &lt;span class="nf"&gt;SetWindowBand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="n"&gt;HWND&lt;/span&gt; &lt;span class="n"&gt;hWnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="n"&gt;HWND&lt;/span&gt; &lt;span class="n"&gt;hwndInsertAfter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="n"&gt;DWORD&lt;/span&gt; &lt;span class="n"&gt;dwBand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GetWindowBand&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;BOOL&lt;/span&gt; &lt;span class="n"&gt;WINAPI&lt;/span&gt; &lt;span class="nf"&gt;GetWindowBand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="n"&gt;HWND&lt;/span&gt; &lt;span class="n"&gt;hWnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="n"&gt;PDWORD&lt;/span&gt; &lt;span class="n"&gt;pdwBand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Calling the APIs?
&lt;/h3&gt;

&lt;p&gt;All those functions are private APIs found in &lt;code&gt;user32.dll&lt;/code&gt;, so you have to use &lt;code&gt;GetProcAdress&lt;/code&gt; to get to them.&lt;br&gt;
But Microsoft implemented some checks to prevent their usage.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GetWindowBand&lt;/code&gt; always works.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CreateWindowInBand/Ex&lt;/code&gt; only works if you pass &lt;code&gt;ZBID_DEFAULT&lt;/code&gt; or &lt;code&gt;ZBID_DESKTOP&lt;/code&gt;
&lt;code&gt;ZBID_UIACCESS&lt;/code&gt; works only with the &lt;code&gt;uiAccess=True&lt;/code&gt;-flag set and code-signing. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SetWindowBand&lt;/code&gt; will never work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Calling them anyway...
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CreateWindowInBand&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To use &lt;code&gt;CreateWindowInBand&lt;/code&gt; with any ZBID, you need to inject a .dll into an immersive process (bright blue in &lt;a href="https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer" rel="noopener noreferrer"&gt;ProcessExplorer&lt;/a&gt;) and call it from there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SetWindowInBand&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SetWindowBand&lt;/code&gt; gets a little more interesting. In order to use that, you have to inject a .dll into &lt;code&gt;explorer.exe&lt;/code&gt; and hook &lt;code&gt;SetWindowBand&lt;/code&gt; with a trampoline.&lt;br&gt;
As soon as the StartMenu opens, or a new window gets created, the function will be called.&lt;br&gt;
Now you can call the original function twice.&lt;br&gt;
Once with a different HWND and ZBID and then with the original parameters.&lt;br&gt;
A full example of this can be found &lt;a href="https://github.com/Alia5/GlosSI/blob/cc89d291ae2f2fcb037da67928ee6a55396685f8/UWPOverlayEnablerDLL/dllmain.cpp" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With the introduction of Windows Store apps, Microsoft also introduced the concept of WindowBands, to more offer more granular control over window z-ordering.&lt;br&gt;
Many Bands are available, but they don't allow you to use them explicitly.&lt;/p&gt;

&lt;p&gt;With a bit of hacking, however, it's completely possible to freely take advantage of any WindowBand.&lt;/p&gt;

&lt;p&gt;And so &lt;a href="https://alia5.github.io/GlosSI/" rel="noopener noreferrer"&gt;GloSC/GlosSI&lt;/a&gt; (My cobbled together tool for SteamInput) users can enjoy stuff like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbehind.flatspot.pictures%2Fcontent%2Fimages%2F2022%2F01%2F2022-01-05_1317.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbehind.flatspot.pictures%2Fcontent%2Fimages%2F2022%2F01%2F2022-01-05_1317.png" alt="GlosSI enabling Steam Overlay with Minecraft UWP edition"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Credits/Sources: &lt;a href="https://blog.adeltax.com/window-z-order-in-windows-10/" rel="noopener noreferrer"&gt;adltax&lt;/a&gt;&lt;/p&gt;

</description>
      <category>uwp</category>
      <category>overlay</category>
      <category>windows</category>
      <category>winapi</category>
    </item>
    <item>
      <title>The ultimate WSL2 setup (updated 2024)</title>
      <dc:creator>Peter Repukat</dc:creator>
      <pubDate>Wed, 08 Dec 2021 23:27:13 +0000</pubDate>
      <link>https://dev.to/alia5/the-ultimate-wsl2-setup-4m08</link>
      <guid>https://dev.to/alia5/the-ultimate-wsl2-setup-4m08</guid>
      <description>&lt;p&gt;This is a crosspost originally from &lt;a href="https://behind.flatspot.pictures/the-ultimate-wsl2-setup/" rel="noopener noreferrer"&gt;my own blog&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Last Update: 10/23/2024&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Ever wondered how to seamlessly blend Windows and Linux in your daily workflow?&lt;br&gt;&lt;br&gt;
My friends and colleagues frequently ask about my WSL setup - both for personal projects and professional work.  &lt;/p&gt;

&lt;p&gt;I used to direct them to an old blog post of mine, but that always required a massive wall of explanatory text, since things have evolved significantly.&lt;br&gt;&lt;br&gt;
So here is my personal "Ultimate WSL2 Setup"&lt;/p&gt;
&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;for everyone that doesn't feel like reading my gibberish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Win 11 (wslg pre-setup)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.microsoft.com/p/windows-terminal/9n0dx20hk701?rtc=1&amp;amp;activetab=pivot:overviewtab" rel="noopener noreferrer"&gt;Windows Terminal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dorssel/usbipd-win" rel="noopener noreferrer"&gt;usbipd-win&lt;/a&gt; (usb passthrough)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yuk7/ArchWSL" rel="noopener noreferrer"&gt;ArchWSL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;zsh (with some plugins)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gerardog/gsudo" rel="noopener noreferrer"&gt;gsudo&lt;/a&gt; (sudo for windows)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/nullpo-head/WSL-Hello-sudo" rel="noopener noreferrer"&gt;wsl-hello-sudo&lt;/a&gt; (using windows hello/fingerpint with wsl-sudo)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/4U6U57/wsl-open" rel="noopener noreferrer"&gt;wsl-open&lt;/a&gt; (open any file/link with native windows executable)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://1-3-3-7.dev/dotfiles/tree/wsl-arch" rel="noopener noreferrer"&gt;my dotfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Custom Kernel for car-hacking stuff&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Terminal: Your Gateway to Command Line Bliss
&lt;/h3&gt;

&lt;p&gt;Before diving into WSL and shell configurations, let's get you set up with a proper terminal emulator. The landscape has evolved significantly, and your options are much better than they were a few years ago.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.microsoft.com/p/windows-terminal/9n0dx20hk701?activetab=pivot:overviewtab" rel="noopener noreferrer"&gt;Windows Terminal&lt;/a&gt; has matured into a fantastic choice with an impressive feature set. The best part? It's blazing fast! They've even added a sweet &lt;a href="https://github.com/microsoft/terminal/blob/main/doc/specs/#653%20-%20Quake%20Mode/#653%20-%20Quake%20Mode.md" rel="noopener noreferrer"&gt;quake-mode&lt;/a&gt; feature recently, making it a worthy replacement for the old "conhost.exe".&lt;/p&gt;

&lt;p&gt;While Windows Terminal has become my daily driver, it does have a few limitations. If you need advanced features like auto-start in hidden-quake mode or separate always-on-top settings for quake-mode and normal-mode instances, &lt;a href="https://conemu.github.io" rel="noopener noreferrer"&gt;ConEmu&lt;/a&gt; remains the most feature-rich alternative - just be prepared for slightly slower performance.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fonts
&lt;/h3&gt;

&lt;p&gt;Next up, let's talk typography. You'll want fonts with extensive glyph support (icons) - I recommend checking out &lt;a href="https://www.nerdfonts.com/#home" rel="noopener noreferrer"&gt;nerd-fonts&lt;/a&gt;. While Windows lacks an official all-in-one installer, you can either use your preferred Windows package manager or cherry-pick specific fonts as I did&lt;/p&gt;
&lt;h3&gt;
  
  
  Windows Sudo: Trust Me, You'll Want This
&lt;/h3&gt;

&lt;p&gt;Here's a game-changer: &lt;a href="https://github.com/gerardog/gsudo" rel="noopener noreferrer"&gt;gsudo&lt;/a&gt;, essentially bringing sudo to Windows.&lt;br&gt;&lt;br&gt;
On Windows 11, it's as simple as running &lt;code&gt;winget install gsudo&lt;/code&gt; in an elevated PowerShell.&lt;br&gt;&lt;br&gt;
Once installed, you can elevate any Windows process/command with a simple &lt;code&gt;gsudo&lt;/code&gt; prefix.&lt;/p&gt;
&lt;h3&gt;
  
  
  WSL
&lt;/h3&gt;

&lt;p&gt;I've fallen in love with Arch Linux's minimalist approach, which fits perfectly within WSL's ecosystem. While Arch isn't officially supported, several excellent distro launchers make it possible. I've had great success with &lt;a href="https://github.com/yuk7/ArchWSL#archwsl" rel="noopener noreferrer"&gt;ArchWSL&lt;/a&gt;, which has proven reliable even in professional settings.&lt;/p&gt;

&lt;p&gt;For a basic installation, you can refer to their excellent guide &lt;a href="https://wsldl-pg.github.io/ArchW-docs/How-to-Setup/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've never used WSL before or start with a fresh Windows install, use &lt;a href="https://docs.microsoft.com/de-de/windows/wsl/install-win10#step-2---check-requirements-for-running-wsl-2" rel="noopener noreferrer"&gt;Microsoft's guide&lt;/a&gt; to install WSL, but install ArchWSL from their GitHub page, instead of any other distro from the Microsoft store.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Systemd&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Recent WSL2 versions finally support Systemd, enabling things like docker without the pesky  "Docker for Windows"-App.&lt;br&gt;&lt;br&gt;
Although it's not enabled by default...&lt;br&gt;&lt;br&gt;
To activate it, add this to &lt;code&gt;/etc/wsl.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[boot]&lt;/span&gt;
&lt;span class="py"&gt;systemd&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  File system gotchas
&lt;/h3&gt;

&lt;p&gt;While recent Windows versions provide built-in access to Linux files, some compatibility quirks remain. I prefer mapping WSL files as a network drive using &lt;code&gt;\\wsl.localhost\&lt;/code&gt; - simple and effective.&lt;/p&gt;

&lt;p&gt;From the Linux side, you can project file permissions and metadata to NTFS, though it requires configuration.&lt;br&gt;&lt;br&gt;
This enables neat tricks like symlinking your Windows-generated SSH folder, eliminating redundant key and config management.&lt;/p&gt;

&lt;p&gt;Here's my battle-tested &lt;code&gt;/etc/wsl.conf&lt;/code&gt; configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# Includes enabling Systemd from above
&lt;/span&gt;&lt;span class="nn"&gt;[boot]&lt;/span&gt;
&lt;span class="py"&gt;systemd&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# Enable extra metadata options by default
&lt;/span&gt;&lt;span class="nn"&gt;[automount]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;root&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/mnt/&lt;/span&gt;
&lt;span class="py"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"metadata,rw,umask=22,fmask=11"&lt;/span&gt;
&lt;span class="py"&gt;mountFsTab&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;false&lt;/span&gt;

&lt;span class="c"&gt;# Enable DNS  even though these are turned on by default, we’ll specify here just to be explicit.
&lt;/span&gt;&lt;span class="nn"&gt;[network]&lt;/span&gt;
&lt;span class="py"&gt;generateHosts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;generateResolvConf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;

&lt;span class="nn"&gt;[interop]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;appendWindowsPath&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  USB Support: Connecting the Physical World
&lt;/h3&gt;

&lt;p&gt;Another feature that is missing from WSL out of the box is support for USB devices.&lt;br&gt;&lt;br&gt;
However, recently (at time of writing) M$ did put some work into it, and posted about &lt;a href="https://devblogs.microsoft.com/commandline/connecting-usb-devices-to-wsl/" rel="noopener noreferrer"&gt;a way to make it happen.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's great news for anyone who's into Arduino or similar stuff or even car-hacking, as I personally find that that kinda stuff is just easier to set up on Linux than on Windows.&lt;/p&gt;

&lt;p&gt;Basically, just install &lt;a href="https://github.com/dorssel/usbipd-win" rel="noopener noreferrer"&gt;usbipd-win&lt;/a&gt;...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;winget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--interactive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--exact&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dorssel.usbipd-win&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Arch users, that's all you need!&lt;br&gt;&lt;br&gt;
From any elevated command prompt, you can manage USB devices with &lt;code&gt;usbipd wsl list&lt;/code&gt; and &lt;code&gt;usbipd wsl attach --busid XX&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;With gsudo, you can run these commands directly from WSL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cmd.exe /c gsudo usbipd wsl list
cmd.exe /c gsudo usbipd wsl attach &lt;span class="nt"&gt;--busid&lt;/span&gt; 4-4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WSL-Open: Seamless integration
&lt;/h3&gt;

&lt;p&gt;Want to make your WSL experience even smoother?&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/4U6U57/wsl-open" rel="noopener noreferrer"&gt;wsl-open&lt;/a&gt; is a must-have tool. It lets you use Linux's standard &lt;code&gt;xdg-open&lt;/code&gt; command to open files and links with native Windows applications. Installation is a breeze via npm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; wsl-open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there is also a non-npm installation described on their GitHub page, if you're not into node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Port Fowards: Reaching the Outside World
&lt;/h2&gt;

&lt;p&gt;While WSL normally forwards network ports to Windows automatically (though it occasionally hiccups 🤷‍♂️), external access remains challenging.&lt;br&gt;&lt;br&gt;
This can be frustrating when you need SSH access or want to quickly share files via a temporary web server.&lt;/p&gt;

&lt;p&gt;Here's a PowerShell script that solves this limitation, allowing direct port forwarding to WSL (also available on &lt;a href="https://gist.github.com/Alia5/f32bf1440e5d705b8ede1a0269d985fc" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# WSL2 network port forwarding script v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;#   for enable script, 'Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope CurrentUser' in Powershell,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;#   for delete exist rules and ports use 'delete' as parameter, for show ports use 'list' as parameter.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;#   written by Daehyuk Ahn, Aug-1-2020&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Display all portproxy information&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;netsh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;portproxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v4tov4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# If elevation needed, start new process&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;Security.Principal.WindowsPrincipal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Security.Principal.WindowsIdentity&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;GetCurrent&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsInRole&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;Security.Principal.WindowsBuiltInRole&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="nx"&gt;Administrator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c"&gt;# Relaunch as an elevated process:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;Start-Process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;powershell.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-File"&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="s1"&gt;'"{0}"'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$MyInvocation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MyCommand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$Args&lt;/span&gt;&lt;span class="s2"&gt; runas"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Verb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RunAs&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# You should modify '$Ports' for your applications&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$Ports&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;667&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Check WSL ip address&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;#wsl /bin/sh -c "ip route get 1 | grep 1. | awk '{print \`$3}'" | Set-Variable -Name "WSL"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;#wsl hostname -i | Set-Variable -Name "WSL"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$WSL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ifconfig eth0 | grep 'inet ' | awk '{print \&lt;/span&gt;&lt;span class="se"&gt;`$&lt;/span&gt;&lt;span class="s2"&gt;2}'"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$WSL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$WSL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$found&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WSL2 cannot be found. Terminate script."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Remove and Create NetFireWallRule&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-NetFireWallRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-DisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'WSL 2 Firewall Unlock'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-ne&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"delete"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;New-NetFireWallRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-DisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'WSL 2 Firewall Unlock'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Outbound&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-LocalPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$Ports&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Allow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Protocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TCP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;New-NetFireWallRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-DisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'WSL 2 Firewall Unlock'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Inbound&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-LocalPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$Ports&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Allow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Protocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TCP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Add each port into portproxy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$Addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;Foreach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$Ports&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"netsh interface portproxy delete v4tov4 listenaddress=&lt;/span&gt;&lt;span class="nv"&gt;$Addr&lt;/span&gt;&lt;span class="s2"&gt; listenport=&lt;/span&gt;&lt;span class="nv"&gt;$Port&lt;/span&gt;&lt;span class="s2"&gt; | Out-Null"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-ne&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"delete"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"netsh interface portproxy add v4tov4 listenaddress=&lt;/span&gt;&lt;span class="nv"&gt;$Addr&lt;/span&gt;&lt;span class="s2"&gt; listenport=&lt;/span&gt;&lt;span class="nv"&gt;$Port&lt;/span&gt;&lt;span class="s2"&gt; connectaddress=&lt;/span&gt;&lt;span class="nv"&gt;$WSL&lt;/span&gt;&lt;span class="s2"&gt; connectport=&lt;/span&gt;&lt;span class="nv"&gt;$Port&lt;/span&gt;&lt;span class="s2"&gt; | Out-Null"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Display all portproxy information&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;netsh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;portproxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v4tov4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Give user to chance to see above list when relaunched start&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"runas"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"runas"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NoNewLine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Press any key to close! '&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="bp"&gt;$null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$Host&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RawUI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'NoEcho,IncludeKeyDown'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pro tip: Avoid using port 22 for your SSH server, as the native Windows SSH server will intercept these connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  [Optional] Custom Kernel: For the Power Users
&lt;/h2&gt;

&lt;p&gt;While most users won't need a custom kernel, it's essential for specific use cases like running SocketCAN for car hacking. Here's how to build and install your own kernel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#get kernel version&lt;/span&gt;
&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;
  5.10.60.1-microsoft-standard-WSL2

&lt;span class="c"&gt;# get matching version, this is mine&lt;/span&gt;
wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-5.10.60.1.tar.gz

&lt;span class="c"&gt;#extract it (change to your kernel version)&lt;/span&gt;
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xf&lt;/span&gt; linux-msft-wsl-5.10.60.1.tar.gz

&lt;span class="c"&gt;# build linux/modules&lt;/span&gt;

&lt;span class="c"&gt;# change to the folder tar extracted too, yours might be different&lt;/span&gt;
&lt;span class="nb"&gt;cd  &lt;/span&gt;WSL2-Linux-Kernel-linux-msft-wsl-5.10.60.1/
&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/config.gz | &lt;span class="nb"&gt;gunzip&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .config
make prepare modules_prepare &lt;span class="nt"&gt;-j&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;expr&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;nproc&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; - 1&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# select your drivers/modules here&lt;/span&gt;
make menuconfig &lt;span class="nt"&gt;-j&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;expr&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;nproc&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; - 1&lt;span class="si"&gt;)&lt;/span&gt;
make modules &lt;span class="nt"&gt;-j&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;expr&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;nproc&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; - 1&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;make modules_install
make &lt;span class="nt"&gt;-j&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;expr&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;nproc&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; - 1&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;make &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# copy it to windows drive, change &amp;lt;yourwindowsloginname&amp;gt; to your windows users &lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;vmlinux /mnt/c/Users/&amp;lt;yourwindowsloginname&amp;gt;/

&lt;span class="c"&gt;#create this file&lt;/span&gt;
vim /mnt/c/Users/&amp;lt;yourwindowsloginname&amp;gt;/.wslconfig

&lt;span class="c"&gt;#with these contents&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;wsl2]
&lt;span class="nv"&gt;kernel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C:&lt;span class="se"&gt;\\&lt;/span&gt;Users&lt;span class="se"&gt;\\&lt;/span&gt;&amp;lt;yourwindowsloginname&amp;gt;&lt;span class="se"&gt;\\&lt;/span&gt;vmlinux

&lt;span class="c"&gt;# exit wsl&lt;/span&gt;
wsl.exe &lt;span class="nt"&gt;--shutdown&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Missing something?
&lt;/h3&gt;

&lt;p&gt;Am I missing something?&lt;br&gt;
Let me know!&lt;/p&gt;

</description>
      <category>wsl2</category>
      <category>windows</category>
      <category>setup</category>
      <category>ultimate</category>
    </item>
  </channel>
</rss>
