<?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: Danny Jones</title>
    <description>The latest articles on DEV Community by Danny Jones (@dnnyjns).</description>
    <link>https://dev.to/dnnyjns</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%2F353674%2Febcf29b2-2a6c-4d33-aca1-42d52c9014a4.jpeg</url>
      <title>DEV Community: Danny Jones</title>
      <link>https://dev.to/dnnyjns</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dnnyjns"/>
    <language>en</language>
    <item>
      <title>Intro to string literal types</title>
      <dc:creator>Danny Jones</dc:creator>
      <pubDate>Sat, 16 May 2020 18:55:11 +0000</pubDate>
      <link>https://dev.to/dnnyjns/into-to-string-literal-types-13o2</link>
      <guid>https://dev.to/dnnyjns/into-to-string-literal-types-13o2</guid>
      <description>&lt;p&gt;Are you using &lt;a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal-types"&gt;string literal types&lt;/a&gt;? They're by far my most favorite feature in TypeScript. In their simplest form, they're used as a set of self-documenting props. In advanced cases, &lt;a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#exhaustiveness-checking"&gt;exhaustiveness type checking&lt;/a&gt; gives you confidence knowing that you'll receive compile errors when making updates without properly handling all cases.&lt;/p&gt;

&lt;p&gt;If you're new to TypeScript and not yet using string literal types, then let's go over three reasons why you'll want to start using them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Self documenting props&lt;/li&gt;
&lt;li&gt;Pairing with Record&amp;lt;K, T&amp;gt;&lt;/li&gt;
&lt;li&gt;Exhaustiveness checking&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Self documenting props
&lt;/h1&gt;

&lt;p&gt;I need a helper function that returns a number when given input of small, medium, or large. This is a pretty common pattern when creating React components and could be used for something as simple as supporting different sizes of buttons. How would I do this without string literal types?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This is probably the worst possible way to handle this. Don't do this!&lt;/em&gt; 🤠&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;getPx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;large&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;size&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;medium&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;12&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;From looking at this, it's pretty clear what props are supported, but I need to look at the code to understand it. What if this is moved to a library? Would I need to go to the readme or to the source code to remind myself which props are supported? This is a quick way to guarantee that nobody uses this helper function.&lt;/p&gt;

&lt;p&gt;Converting this to use a string literal type does two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Defines a clear set of accepted properties. If you're using an IDE with IntelliSense then you'll see supported props as you type.&lt;/li&gt;
&lt;li&gt;Compile time error when using unsupported props:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="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;Sizes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;small&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;medium&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;large&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;getPx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sizes&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;large&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;size&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;medium&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;12&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;getPx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;xlarge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Argument of type '"xlarge"' is not assignable to parameter of type 'Sizes'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h1&gt;
  
  
  Pairing with Record&amp;lt;K, T&amp;gt;
&lt;/h1&gt;

&lt;p&gt;Pairing string literal types with the &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkt"&gt;Record&amp;lt;K, T&amp;gt;&lt;/a&gt; utility type is a slick pattern to use when you want to cleanup your code.&lt;/p&gt;

&lt;p&gt;Let's apply this pattern to &lt;code&gt;getPx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Sizes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;small&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;medium&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;large&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;sizes&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="nx"&gt;Sizes&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="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;small&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;large&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&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;getPx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sizes&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="nx"&gt;sizes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;size&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;That's a lot cleaner! Not only is it easier to add new sizes, but you'll also receive an error if you update &lt;code&gt;Sizes&lt;/code&gt; without updating the &lt;code&gt;sizes&lt;/code&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add a new size without updating `sizes`&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Sizes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;small&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;medium&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;large&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;xlarge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Property 'xlarge' is missing in type '{ small: number; medium: number; large: number; }' but required in type 'Record&amp;lt;Sizes, number&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h1&gt;
  
  
  Exhaustiveness checking
&lt;/h1&gt;

&lt;p&gt;Another lesser known feature of string literal types is that you can benefit from what's known as &lt;a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#exhaustiveness-checking"&gt;exhaustiveness type checking&lt;/a&gt; when using switch statements. This means that TypeScript follows the flow of your code to determine if all cases are covered. If your code is too complex to work with the Record&amp;lt;K, T&amp;gt; pattern, then using exhaustiveness checking is a way to remove brittleness from your code.&lt;/p&gt;

&lt;p&gt;This can be demonstrated most easily by converting &lt;a href="https://reactjs.org/docs/hooks-reference.html#usereducer"&gt;this reducer&lt;/a&gt; to TypeScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;ActionType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decrement&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;increment&lt;/span&gt;&lt;span class="dl"&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;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionType&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;State&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&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;const&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;State&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;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&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="s2"&gt;increment&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decrement&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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="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;The key part of making this work is to remove the &lt;code&gt;default&lt;/code&gt; case from the switch statement. By removing the &lt;code&gt;default&lt;/code&gt; case, you'll run into a compile error when updating &lt;code&gt;ActionType&lt;/code&gt; without updating the switch statement to handle the new case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add "reset" to `ActionType'&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ActionType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decrement&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;increment&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;reset&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Function lacks ending return statement and return type does not include 'undefined'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;String literal types solve a handful of problems that help developers write clean, maintainable, and scalable code.&lt;/p&gt;

</description>
      <category>typescript</category>
    </item>
    <item>
      <title>Move fast with GraphQL, Rails, and TypeScript</title>
      <dc:creator>Danny Jones</dc:creator>
      <pubDate>Wed, 06 May 2020 22:55:48 +0000</pubDate>
      <link>https://dev.to/onehq/move-fast-38il</link>
      <guid>https://dev.to/onehq/move-fast-38il</guid>
      <description>&lt;p&gt;Here at OneHQ, we've had great success using GraphQL with Rails and TypeScript. I wanted to take the time to show off a couple techniques that we use to enable developers to move fast &lt;del&gt;and break things&lt;/del&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dynamically create GraphQL types in Ruby&lt;/li&gt;
&lt;li&gt;Commit the GraphQL schema to version control&lt;/li&gt;
&lt;li&gt;Auto-generate GraphQL types in TypeScript&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Dynamically create GraphQL types in Ruby
&lt;/h3&gt;

&lt;p&gt;Our database schemas are continuously evolving, and we didn't want the overhead of having to keep our tables, models, and GraphQL types in sync. ActiveRecord gets around this by using meta-programming to dynamically analyze the database to generate methods. Why couldn't we do the same with GraphQL? &lt;/p&gt;




&lt;p&gt;We could and we did! Thus was born &lt;a href="https://github.com/OneHQ/hq-graphql"&gt;hq-graphql&lt;/a&gt;. hq-graphql is a wrapper around &lt;a href="https://graphql-ruby.org/"&gt;graphql-ruby&lt;/a&gt; that does all of the necessary magic to integrate with ActiveRecord. Instead of creating a bajillion types with a bazillion fields...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AdvisorType&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;GraphQL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Object&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:created_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;ISO8601DateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="c1"&gt;# &amp;lt;bazillion fields go here (use your imagination)&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;# &amp;lt;bazillion fields go here (use your imagination)&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;# &amp;lt;bazillion fields go here (use your imagination)&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can now simply reference the model to dynamically create fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AdvisorType&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HQ&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;GraphQL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Object&lt;/span&gt;
  &lt;span class="n"&gt;with_model&lt;/span&gt; &lt;span class="s2"&gt;"Advisor"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h3&gt;
  
  
  Commit the GraphQL schema to version control
&lt;/h3&gt;

&lt;p&gt;Once we began creating types dynamically, I feared that devs would add/remove columns from our schema without realizing that it affected GraphQL. Too much magic can be bad, especially if there isn't feedback for when something changes.&lt;/p&gt;

&lt;p&gt;For this reason, we dump and commit the GraphQL IDL (Interface Definition Language) to a file named schema.graphql whenever the schema changes. Checking in the schema to version control helps both the developer and code reviewer identify breaking changes before they hit production.&lt;/p&gt;

&lt;p&gt;To make things &lt;em&gt;even&lt;/em&gt; easier, we created a test that compares the current schema with what's committed so that they can't forget to check it in! This ensures that our CI process fails whenever a dev forgets to update the schema file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto-generate GraphQL types in TypeScript
&lt;/h3&gt;

&lt;p&gt;Another fear of mine was that we would update the schema and forget to update the front-end!&lt;sup&gt;(I'm afraid of a lot)&lt;/sup&gt; Of course you could write tests to circumvent this (and we do), but what if we could auto-generate our GraphQL types in TypeScript instead of creating them by hand? This would give us another layer of protection and allow for us to easily correct any disparities when something does change.&lt;/p&gt;




&lt;p&gt;Good news! This was the easiest of all our problems as there's already a tool out there that does this. &lt;a href="https://github.com/apollographql/apollo-tooling#apollo-clientcodegen-output"&gt;Apollo Codegen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Point codegen to the code that uses GraphQL and run it! It pulls out any GraphQL queries and uses introspection to dynamically generate your types. If the GraphQL queries in your client don't align with your back-end, then it throws an error and lets you know what's wrong&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;apollo client:codegen src/graphql/types/index.ts &lt;span class="nt"&gt;--endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://[::1]:8080/graphql &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;typescript &lt;span class="nt"&gt;--includes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'src/graphql/**/**/*.{ts,tsx}'&lt;/span&gt; &lt;span class="nt"&gt;--tagName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gql &lt;span class="nt"&gt;--addTypename&lt;/span&gt; &lt;span class="nt"&gt;--outputFlat&lt;/span&gt;
  ⠏ Loading Apollo Project
    Generating query files
.../src/graphql/application/useApplications.ts: Cannot query field &lt;span class="s2"&gt;"names"&lt;/span&gt; on &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="s2"&gt;"Application"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; Did you mean &lt;span class="s2"&gt;"name"&lt;/span&gt;?
ToolError: Validation of GraphQL query document failed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






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

&lt;p&gt;Using meta-programming to generate types has saved us countless hours at OneHQ by allowing us to focus on what really matters. &lt;strong&gt;But beware!!!&lt;/strong&gt; Using meta-programming without checks and balances in your code review process could lead to a broken app.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>rails</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
