<?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: Paul Guilbert</title>
    <description>The latest articles on DEV Community by Paul Guilbert (@pguilbert).</description>
    <link>https://dev.to/pguilbert</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%2F20005%2Ff6d0ca05-cba2-4731-908a-12220c4766a6.jpg</url>
      <title>DEV Community: Paul Guilbert</title>
      <link>https://dev.to/pguilbert</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pguilbert"/>
    <language>en</language>
    <item>
      <title>An alternative solution to Typescript enums</title>
      <dc:creator>Paul Guilbert</dc:creator>
      <pubDate>Sat, 09 Dec 2023 23:07:28 +0000</pubDate>
      <link>https://dev.to/pguilbert/a-remplacement-for-typescript-enums-4705</link>
      <guid>https://dev.to/pguilbert/a-remplacement-for-typescript-enums-4705</guid>
      <description>&lt;p&gt;Enums are quite handy to define a set of named constants. In the TypeScript world, enums hold a unique position as both a type and a value. &lt;/p&gt;

&lt;p&gt;However, enum comes with drawbacks... &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Enums and const enums, are an exception to the Typescript structural typing. Meaning that Level1.INFO !== Level2.INFO !== 'INFO' even when both Level1.Info and Level2.INFO are set to 'INFO'.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enums are not necessarily enumerable at runtime, and &lt;code&gt;Object.values(MyEnums)&lt;/code&gt; can have unexpected results.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enums and const enums, are more a legacy feature than a recommended one.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's take an example:&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;enum&lt;/span&gt; &lt;span class="nx"&gt;Level&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;VERBOSE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VERBOSE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;NORMAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NORMAL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DEBUG&lt;/span&gt;&lt;span class="dl"&gt;'&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Level&lt;/span&gt;&lt;span class="p"&gt;)&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DEBUG&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 '"DEBUG"' is not assignable to parameter of type 'Level'&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;Level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ✅&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allLevels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;// allLevels = ["NONE", 0, "VERBOSE", "NORMAL", "DEBUG"] 🤔&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While it operates as intended, the behavior of enums may seem somewhat strange to a TypeScript user.&lt;/p&gt;

&lt;h2&gt;
  
  
  The alternative solution
&lt;/h2&gt;

&lt;p&gt;Fortunately, TypeScript offers features that, when combined, provide similar functionality to enums:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;const object&lt;/li&gt;
&lt;li&gt;union type&lt;/li&gt;
&lt;li&gt;value and a type can coexist with the same name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This leads to the following code that "fixed" the unwanted behavior of enums:&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;Level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;NONE&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="na"&gt;VERBOSE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VERBOSE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;NORMAL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NORMAL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DEBUG&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Level&lt;/span&gt; &lt;span class="o"&gt;=&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;Level&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;Level&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Level&lt;/span&gt;&lt;span class="p"&gt;)&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DEBUG&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&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;Level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ✅&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allLevels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;// [0, "VERBOSE", "NORMAL", "DEBUG"] ✅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The clear advantage of this approach is that, in most cases, it's possible to seamlessly replace enums without modifying existing code that uses them.&lt;/p&gt;

&lt;p&gt;Additionally, the union type can be simplified using the utility 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;UnionOfPropertyTypes&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;object&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="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;Resulting in a cleaner declaration:&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;Level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;NONE&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="na"&gt;VERBOSE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VERBOSE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;NORMAL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NORMAL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DEBUG&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UnionOfPropertyTypes&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;Level&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A reason to choose React Native over Flutter for your next web application</title>
      <dc:creator>Paul Guilbert</dc:creator>
      <pubDate>Thu, 18 May 2023 10:15:54 +0000</pubDate>
      <link>https://dev.to/pguilbert/a-reason-to-choose-react-native-over-flutter-for-your-next-web-application-3k9e</link>
      <guid>https://dev.to/pguilbert/a-reason-to-choose-react-native-over-flutter-for-your-next-web-application-3k9e</guid>
      <description>&lt;p&gt;This post aims to summarize my thoughts on Flutter vs. React Native specifically for web development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flutter
&lt;/h2&gt;

&lt;p&gt;The purpose of Flutter Web is not to create websites; rather, it focuses on making apps available in the browser. Embracing web standards is not the objective here, instead, the goals are to ensure fidelity and consistency across platforms. For that, with the help of &lt;a href="https://docs.flutter.dev/platform-integration/web/renderers"&gt;CanvasKit&lt;/a&gt;, the browser functions as a Flutter screen, enabling the rendering of your mobile/desktop app within a canvas, and bypassing many built-in browser features. This is why the &lt;a href="https://docs.flutter.dev/platform-integration/web/faq"&gt;Flutter documentation states the following:&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Not every web page makes sense in Flutter, but we think Flutter is particularly suited for app-centric experiences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Progressive Web Apps&lt;/li&gt;
&lt;li&gt;Single Page Apps&lt;/li&gt;
&lt;li&gt;Existing Flutter mobile apps&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  React Native
&lt;/h2&gt;

&lt;p&gt;React Native shares a similar objective, which is to ensure cross-platform consistency. However, when it comes to web development, React Native has a significant advantage: it relies on JavaScript, HTML, and CSS. No need to download a 2MB web assembly; no need to reimplement the wheel to make the scrollbar work or &lt;em&gt;hack&lt;/em&gt; the accessibility tree to make the canvas accessible: React Native Web relies on the browser rendering engine and existing javascript APIs.&lt;/p&gt;

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

&lt;p&gt;It makes a lot of sense to choose Flutter if you are already familiar with Dart or if you intend to migrate an existing Flutter app to the web. But otherwise, if you make a web app and plan to target other platforms in the future I would not hesitate to go with React Native!&lt;/p&gt;

&lt;p&gt;Obviously, you should compare Flutter and React Native on Android and iOS to make a final choice (and that would deserve another post). However, whatever you read elsewhere, don't forget that you can use skia (Flutter's engine) &lt;a href="https://github.com/Shopify/react-native-skia"&gt;inside a React Native application.&lt;/a&gt;😉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Flutter does support HTML/CSS rendering as a replacement for CanvasKit.  (but I don't really understand why they maintain two renderers in parallel ?). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Illustration image: I ask bing chat for "an epic combat between Flutter and React Native, colorfull and illustrated"&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>reactnative</category>
      <category>flutter</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
