<?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>Forem: koraflux</title>
    <description>The latest articles on Forem by koraflux (@koraflux).</description>
    <link>https://forem.com/koraflux</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%2F943286%2Fce029350-f5d8-410e-ad74-5e0b9fa14705.jpg</url>
      <title>Forem: koraflux</title>
      <link>https://forem.com/koraflux</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/koraflux"/>
    <language>en</language>
    <item>
      <title>Typescript advanced bits: function overloading, never and unknown types</title>
      <dc:creator>koraflux</dc:creator>
      <pubDate>Thu, 10 Nov 2022 15:29:34 +0000</pubDate>
      <link>https://forem.com/koraflux/typescript-advanced-bits-function-overloading-never-and-unknown-types-1kb8</link>
      <guid>https://forem.com/koraflux/typescript-advanced-bits-function-overloading-never-and-unknown-types-1kb8</guid>
      <description>&lt;p&gt;Typescript is a powerful tool that helps build reliable products, develop codebases that scale, and improve the developer experience. While it's quite popular nowadays, some aspects are sometimes overlooked.&lt;/p&gt;

&lt;p&gt;As a massive fan of Typescript, I want to draw your attention to some of them and talk a bit about how they work, what could be the potential use cases and what benefits they bring. In this article, we'll be looking at function overloading as well as &lt;code&gt;unknown&lt;/code&gt; &amp;amp; &lt;code&gt;never&lt;/code&gt; types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Function overloading
&lt;/h2&gt;

&lt;p&gt;Sometimes you may find yourself in a situation where you want a function that needs to work with more than one set of parameters and produce results of different types. Usually, to achieve this, we can use optional parameters and unions. But in some cases, this does not let us describe how parameters and return types are associated concisely enough. So we lose on readability and quality of hints from our IDE. This is where function overloading can help us.&lt;/p&gt;

&lt;p&gt;Function overloading in Typescript is a fantastic feature that lets you define multiple function signatures one after another, describing what the function will return depending on what parameters are passed.&lt;/p&gt;

&lt;p&gt;To do this, we write two kinds of signatures - overloading signatures and implementation signatures. Overloading signatures does not have an implementation (function body) and just defines the typings. It's important to remember that the implementation signature should be compatible with all the overloading signatures.&lt;/p&gt;

&lt;p&gt;Let's look at an example from an imaginary car-renting app. We need a universal function for getting a car booking price. It accepts some information about the car and returns a single price or an array of prices, depending on parameters. Also, if a callback is passed, then it will be called with the price, and in this case, the function will return. Depending on what parameters are passed, it calls two different functions to retrieve the price from the backend (that part is simplified for explanatory purposes). This is what it may look like:&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;getCarPricesByCarParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;carType&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;city&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;distance&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="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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&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;getPriceByCarId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carId&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="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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBookingPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carId&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="kr"&gt;number&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBookingPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;carId&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;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&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="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBookingPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;carType&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;city&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;distance&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="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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBookingPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;carIdOrType&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;callbackOrCity&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;price&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="k"&gt;void&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;distance&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="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;callbackOrCity&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// we're returning a number[] type&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getCarPricesByCarParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;carIdOrType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;callbackOrCity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;callbackOrCity&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getPriceByCarId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carIdOrType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;callbackOrCity&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="c1"&gt;// we're not returning anything here&lt;/span&gt;
    &lt;span class="c1"&gt;// (so function has void return type)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// we're returning a number type&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is helpful when the function is complex and returns multiple types. Function overloading enables us to establish strict relationships between parameter types and returned types. If your function gets this complex, a good way to deal with it might be as well splitting it into multiple functions.&lt;/p&gt;

&lt;p&gt;Another alternative to function overloading is using Union types in parameters. It's a good idea to experiment with both approaches to identify what feels right for your specific case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unknown type
&lt;/h2&gt;

&lt;p&gt;Apart from well-known and straightforward primitive types like &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, and &lt;code&gt;boolean&lt;/code&gt;, the typescript type system has some types that could confuse new developers. Those are &lt;code&gt;never&lt;/code&gt; and &lt;code&gt;unknown&lt;/code&gt;. Let's look at those types, what they mean and how they can help us.&lt;/p&gt;

&lt;p&gt;Unknown type represents a set of all possible values of every possible type. If we declare a variable of this type, any value can be assigned to it. According to &lt;a href="https://en.wikipedia.org/wiki/Set_theory" rel="noopener noreferrer"&gt;set theory&lt;/a&gt; that Typescripts heavily relies on in its type system, &lt;code&gt;unknown&lt;/code&gt; represents a top type (another top type is &lt;code&gt;any&lt;/code&gt;). It means it can describe any possible value.&lt;/p&gt;

&lt;p&gt;A good way to think about &lt;code&gt;unknown&lt;/code&gt; is that it's a more typesafe version of &lt;code&gt;any&lt;/code&gt;. The difference with &lt;code&gt;any&lt;/code&gt; is that if we type something as &lt;code&gt;any&lt;/code&gt; Typescript permits us to do anything with it. For example, access any properties as if they exist. If you declare a variable of &lt;code&gt;unknown&lt;/code&gt; type, Typescript won't let you use it (i.e. access nested properties, call methods or perform operations) unless you narrow it down to a more specific type. And this is much more typesafe.&lt;/p&gt;

&lt;p&gt;For this, you can use type guards with typeof, instanceof or other &lt;a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html" rel="noopener noreferrer"&gt;type narrowing techniques&lt;/a&gt; or assertions. Using generally makes your code less typesafe, so other type guarding techniques are preferable in most cases.&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;let&lt;/span&gt; &lt;span class="nx"&gt;someValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;

&lt;span class="c1"&gt;// TS will complain about the following:&lt;/span&gt;

&lt;span class="nx"&gt;someValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// error&lt;/span&gt;
&lt;span class="nx"&gt;someValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someOtherValue&lt;/span&gt;   &lt;span class="c1"&gt;// error&lt;/span&gt;
&lt;span class="nf"&gt;someValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;               &lt;span class="c1"&gt;// error&lt;/span&gt;

&lt;span class="c1"&gt;// But if we narrow the type down, &lt;/span&gt;
&lt;span class="c1"&gt;// TS will understand what it is and let us use it.&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;typeOf&lt;/span&gt; &lt;span class="nx"&gt;someValue&lt;/span&gt; &lt;span class="o"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&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;A good way to significantly improve the reliability of your app is via improving type-safety by moving away from using &lt;code&gt;any&lt;/code&gt; to &lt;code&gt;unknown&lt;/code&gt;. One relevant example could be when you type your backend responses and when stringifying JSON to using &lt;code&gt;unknown&lt;/code&gt; combined with some sort of runtime type checking. It can be done either by using built-in functionality like type guards or using an external library like &lt;a href="https://gcanti.github.io/io-ts/" rel="noopener noreferrer"&gt;io-ts&lt;/a&gt;, &lt;a href="https://github.com/colinhacks/zod" rel="noopener noreferrer"&gt;zod&lt;/a&gt; or &lt;a href="https://github.com/jquense/yup" rel="noopener noreferrer"&gt;yup&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Never type
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;never&lt;/code&gt; is a primitive type in Typescript representing a &lt;a href="https://en.wikipedia.org/wiki/Bottom_type" rel="noopener noreferrer"&gt;bottom type&lt;/a&gt;. It is used to describe a type that should never occur. This could be a return type of function that throws an error unconditionally or a state that you want to avoid.&lt;/p&gt;

&lt;p&gt;One particularly helpful use case is using it as a way to ensure that all the variations of a particular data structure are handled.&lt;/p&gt;

&lt;p&gt;For example, imagine we are building a car renting app, and we have a function that should handle all car types, returning a description for each of them. So we can add a simple shouldNotBeReached helper using &lt;code&gt;never&lt;/code&gt; type, and rest assured that once the new car type is added to the codebase, the Typescript will let us know that it needs to be handled.&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;shouldNotBeReached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This should not be reached&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CarType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hedgeback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCarTypeDescription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CarType&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="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hedgeback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;So basically it is a two or four-door car with a tailgate that flips upwards&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Well, it is a car designed for getting somewhere really fast and look cool in the process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;shouldNotBeReached&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carType&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;Later on, we may want to add some other kind of cars to our app, let's say an SUV. It's easy to forget to update all the functions dealing with this type. To avoid this, we'll add a simple function to the default case of the switch statement. It will make sure Typescript reminds us to handle that new car type.&lt;/p&gt;

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

&lt;p&gt;In this article, we explored three advanced Typescript features along with some use cases. Function overloading can be helpful when working with functions that can accept different sets of parameters and return different types depending on that. Using &lt;code&gt;unknown&lt;/code&gt; and &lt;code&gt;never&lt;/code&gt; types helps us write more robust and typesafe code and avoid bugs.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building hotkeys in React apps</title>
      <dc:creator>koraflux</dc:creator>
      <pubDate>Tue, 08 Nov 2022 13:08:01 +0000</pubDate>
      <link>https://forem.com/koraflux/building-hotkeys-in-react-apps-2p5d</link>
      <guid>https://forem.com/koraflux/building-hotkeys-in-react-apps-2p5d</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Using hotkeys is a great way to let your web app users get more done faster.&lt;/p&gt;

&lt;p&gt;It works even better for power users and complex internal applications where your users spend a lot of time, like systems for content editing, monitoring systems or support tools.&lt;/p&gt;

&lt;p&gt;In this article, first, we'll look at some design aspects to keep in mind when implementing hotkeys in an app and ways to make hotkeys convenient for the end user. Then we will do basic hotkeys implementation and look at how to add hotkeys to React application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hotkey Integration Preparations
&lt;/h2&gt;

&lt;p&gt;Stick to three hotkey development guidelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discoverability: familiarise your users with hotkeys. Use onboarding, walkthroughs, labels or tooltips to help users learn about your hotkeys system&lt;/li&gt;
&lt;li&gt;Memorability: hotkeys and key combos need to be simple and memorable&lt;/li&gt;
&lt;li&gt;Compatibility: avoid situations where your hotkeys conflict with existing system-wide or browser shortcuts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Make a Plan
&lt;/h2&gt;

&lt;p&gt;Define a list of actions demanding hotkey implementation. It is helpful to pursue a structured approach, starting with mapping out the user stories in your application and defining app sections. Then split your user stories into actions ranked by importance and usage frequency. Leveraging user feedback and analytics can be very helpful here. All the actions could be divided in two big groups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Global actions include navigation between app parts and launching important functionality. Generally, it makes sense to implement it on the top level of the app (e.g. as a react wrapper component or context).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contextual actions, such as controlling modal windows or popups, should be implemented at the relevant component level (modal window, multi-step form, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Pick the Hotkeys
&lt;/h2&gt;

&lt;p&gt;Think of the hotkeys and key combos. Remember that they should be memorable and non-conflicting with browser or OS hotkeys. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Keep context and users in mind. What OS they are using, other running apps, preferred browser hotkeys, such as native browser search for content-rich websites.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Steer clear of the overloaded classic key combos&lt;br&gt;
Ctrl + N, Ctrl + O, Ctrl + S, Ctrl + P, Ctrl + W &amp;amp; Ctrl + C, Ctrl + Z, Ctrl + F&lt;br&gt;
Alt + F1, F2, F3…&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Decide if you want to use&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single hotkeys&lt;/li&gt;
&lt;li&gt;Combinations or&lt;/li&gt;
&lt;li&gt;Sequences - keep in mind that they should not conflict with single hotkeys&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Settling on one approach will simplify hotkeys for the users. &lt;/p&gt;

&lt;p&gt;Single-key hotkeys are easier to use and remember, especially if they're assigned to actions corresponding with key letters. However, this allows for accidental keypresses and a smaller number of possible hotkeys. There are more options with combinations, but some of them will be already used by OS and browser hotkeys. &lt;/p&gt;

&lt;p&gt;The sequences approach works for assigning lots of actions, giving you the biggest freedom of options and number of available combos. For example, it’s used in Gmail. But if you pick this route, avoid using single hotkeys since that will lead to conflicts and a poor UX. You can override browser hotkeys by calling &lt;code&gt;event.preventDefault()&lt;/code&gt; but think twice before you do it as it can be super annoying to your users sometimes.&lt;/p&gt;

&lt;p&gt;After deciding what hotkeys you will assign to your actions, go to your app and try to use them as if they are already there. This will put you in users' shoes and let you identify what works well and what could be improved.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Think About Informing the User
&lt;/h2&gt;

&lt;p&gt;Find a way to implement hotkey information in your design. Some of the frequently used tools include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Labels&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpl76bt71p3ocp22flcnq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpl76bt71p3ocp22flcnq.png" alt=" " width="770" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tooltips&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fok07f1hdj43fjd1fuee2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fok07f1hdj43fjd1fuee2.png" alt=" " width="375" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Underlined letters in buttons corresponding to hotkeys&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frei8u8slmryh9qkvsvu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frei8u8slmryh9qkvsvu6.png" alt=" " width="396" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hotkey maps&lt;/strong&gt; &lt;br&gt;
For the best discoverability and memorability, it’s great to add a hotkey map, i.e. a page or a  modal window with the list of all available actions in the app.&lt;/p&gt;

&lt;p&gt;If there are many hotkeys, a search with a filter may be added on top of the map. Here are some examples of hotkey maps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.pivotaltracker.com/help/articles/keyboard_shortcuts/" rel="noopener noreferrer"&gt;Pivotal tracker &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://trello.com/shortcuts" rel="noopener noreferrer"&gt;Trello&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codesandbox.io/docs/learn/repositories/shortcuts" rel="noopener noreferrer"&gt;Codesandbox&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the way, in all the examples above, users can see those hotkey maps by hitting a '?' key. You can consider following this best practice as well. &lt;/p&gt;

&lt;p&gt;As a result, you have a list of hotkeys and informational design elements to get users up to speed. Now we can move on to implementation.&lt;/p&gt;

&lt;p&gt;For internal app interfaces, which users think of as their main work tools, consider making hotkeys customisable so that users can reassign the keys. This could be useful for the most advanced users.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementing Hotkeys in React
&lt;/h2&gt;

&lt;p&gt;Let’s dive into how hotkeys can be implemented in a React app, look into possible improvements and go over some popular hotkeys libraries that could be helpful to build hotkeys system for your app.&lt;/p&gt;
&lt;h3&gt;
  
  
  Adding Hotkeys
&lt;/h3&gt;

&lt;p&gt;This is what the most basic TypeScript hotkey implementation looks like. All hotkeys implementations are based on event listener, attached either to the document object or a specific DOM node. &lt;/p&gt;

&lt;p&gt;We can use keydownevent to track keyboard presses by the user. Note that we’ve added a check for the &lt;code&gt;event.repeat&lt;/code&gt; property to neutralise double clicks.&lt;/p&gt;

&lt;p&gt;You can always check out all keyboardevents properties on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#properties" rel="noopener noreferrer"&gt;MDN&lt;/a&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;const&lt;/span&gt; &lt;span class="nx"&gt;setupHotkeys&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="p"&gt;{&lt;/span&gt;
 &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keydown&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;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KeyboardEvent&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrlKey&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;l&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="c1"&gt;// do what you want to do when CTRL + L is pressed &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;h3&gt;
  
  
  Hotkeys in a React App
&lt;/h3&gt;

&lt;p&gt;Now let’s implement basic hotkeys as a hook for a React app. &lt;/p&gt;

&lt;p&gt;We are using the &lt;code&gt;useLayoutEffect&lt;/code&gt; hook and useRef hooks to recall the most up to date callback to avoid bugs. Here is a very nice &lt;a href="https://kentcdodds.com/blog/useeffect-vs-uselayouteffect" rel="noopener noreferrer"&gt;article&lt;/a&gt; explaining how &lt;code&gt;useLayoutEffect&lt;/code&gt; hook works just in case.&lt;/p&gt;

&lt;p&gt;We’re also using the &lt;code&gt;useEffect&lt;/code&gt; callback to attach the listener. Please note that we are removing the event listener in a function that gets returned by the &lt;code&gt;useEffect&lt;/code&gt; hook. (Here is the &lt;a href="https://reactjs.org/docs/hooks-effect.html" rel="noopener noreferrer"&gt;documentation &lt;/a&gt; for &lt;code&gt;useEffect&lt;/code&gt; hook). We do this to ensure we don’t leave the listener attached when the component is removed from dom - this is needed to avoid memory leaks.&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;const&lt;/span&gt; &lt;span class="nx"&gt;useHotkeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nx"&gt;key&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;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KeyboardEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;callbackRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="nf"&gt;useLayoutEffect&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="nx"&gt;callbackRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;

 &lt;span class="nf"&gt;useEffect&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KeyboardEvent&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;callbackRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&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;key&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;Let’s now implement support for combos.&lt;/p&gt;

&lt;p&gt;We start by adding an additional parameter, like a combination key or a modifier - Alt, Ctrl, Shift, and the meta key (Windows logo key or the Mac command key). To support the combination, we’ll add an additional check in the handler so that the app reacts only when the key is pressed in a combination with a modifier key.&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;CombinationKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ctrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meta&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shift&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useHotkeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nx"&gt;key&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;combinationKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;CombinationKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KeyboardEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;callbackRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="nf"&gt;useLayoutEffect&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="nx"&gt;callbackRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;

 &lt;span class="nf"&gt;useEffect&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KeyboardEvent&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;combinationKey&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;event&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;combinationKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Key`&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
       &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;
     &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;callbackRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&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;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;combinationKey&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;h2&gt;
  
  
  React Libraries for Hotkeys
&lt;/h2&gt;

&lt;p&gt;There are lots of hotkey development libraries for React apps, one of the most popular ones being &lt;code&gt;react-hotkeys-hook&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An example of how hotkey implementation works in this library:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useHotkeys&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;react-hotkeys-hook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Component&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="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;useHotkeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ctrl+j&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* do something */&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="cm"&gt;/* some jsx */&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;Here’s some other hotkey libraries to check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jaywcjlove/react-hotkeys" rel="noopener noreferrer"&gt;https://github.com/jaywcjlove/react-hotkeys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/iamnautilusjungle/mousetrap-react" rel="noopener noreferrer"&gt;https://gitlab.com/iamnautilusjungle/mousetrap-react&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Hotkey functionality can also be implemented using other libraries, such as Blueprint.js: &lt;a href="https://blueprintjs.com/docs/#core/hooks/use-hotkeys" rel="noopener noreferrer"&gt;https://blueprintjs.com/docs/#core/hooks/use-hotkeys&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;We looked at some ways of building and implementing hotkey systems in React apps. When developing hotkeys, our priority should always be usability and comfort. Well-designed hotkeys can save tons of time for your users and make them happy so it's worth considering hotkeys in your app.&lt;/p&gt;

&lt;p&gt;If you found this interesting and want to know more, here are some cool articles on this topic that I've used while researching:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.prototypr.io/keyboard-shortcuts-creation-d5ae2663fdea" rel="noopener noreferrer"&gt;Keyboard Shortcuts Creation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sashika.medium.com/j-k-or-how-to-choose-keyboard-shortcuts-for-web-applications-a7c3b7b408ee" rel="noopener noreferrer"&gt;J, K, or How to choose keyboard shortcuts for web applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knock.app/blog/how-to-design-great-keyboard-shortcuts" rel="noopener noreferrer"&gt;How to design great keyboard shortcuts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>ux</category>
    </item>
  </channel>
</rss>
