<?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: Louis</title>
    <description>The latest articles on DEV Community by Louis (@louisgv).</description>
    <link>https://dev.to/louisgv</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%2F50980%2F33007336-32f3-47e2-845d-03e380f495d1.png</url>
      <title>DEV Community: Louis</title>
      <link>https://dev.to/louisgv</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/louisgv"/>
    <language>en</language>
    <item>
      <title>18 Reasons to Use TypeScript Since Yesterday.</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Wed, 04 Jan 2023 23:12:54 +0000</pubDate>
      <link>https://dev.to/louisgv/18-reasons-to-use-typescript-since-yesterday-42ci</link>
      <guid>https://dev.to/louisgv/18-reasons-to-use-typescript-since-yesterday-42ci</guid>
      <description>&lt;p&gt;If you're anything like me, you use Typescript because you need to. Your first startup in 2013 had a gigantic Angular.js codebase written in pure JS, and you were a scrappy hacker who thought he could change the world by plowing through the code and single-handedly maintaining it all.&lt;/p&gt;

&lt;p&gt;After a huge QoL refactor, you learned that the time it took was not worth the ROI and that you needed a tool. You wanted something that could solve the problem systematically but is still lenient enough for you to move fast while not being some quick annotation with arcane tooling that is not smart enough to rename your function argument.&lt;/p&gt;

&lt;p&gt;After trying out Flow, Haxe, ReScript, Clojure... you found TypeScript. The light clicked in your head💡&lt;/p&gt;

&lt;p&gt;In this article, I am going to hype the $$$$ out of TypeScript and why you, yes, you, MUST use it. Having used it since 2015, I have seen it all - slow as $$$$ script runtime, messy type collusion, enum not working as expected, and did someone mention &lt;code&gt;emitDecoratorMetadata&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;But hey, eight years in the trench, why didn't I just switch to Rust, C#, Zig, Dart, or some other "better" language?&lt;/p&gt;

&lt;p&gt;Read on.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  👉 Table Of Contents (TOC).
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is Typescript?&lt;/li&gt;
&lt;li&gt;Should I use It?&lt;/li&gt;
&lt;li&gt;Powers of Typescript.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Ease of Learning&lt;/li&gt;
&lt;li&gt;Flexible Type Checking System&lt;/li&gt;
&lt;li&gt;Concise and Readable Syntax&lt;/li&gt;
&lt;li&gt;Intuitive Syntax&lt;/li&gt;
&lt;li&gt;Modern Tooling&lt;/li&gt;
&lt;li&gt;High Productivity&lt;/li&gt;
&lt;li&gt;Realistic Promises&lt;/li&gt;
&lt;li&gt;Flexibility&lt;/li&gt;
&lt;li&gt;Large Community&lt;/li&gt;
&lt;li&gt;Clean Code Made Easy&lt;/li&gt;
&lt;li&gt;A JS Superset&lt;/li&gt;
&lt;li&gt;A Compiled Language&lt;/li&gt;
&lt;li&gt;Reduced Tooling&lt;/li&gt;
&lt;li&gt;High Performance&lt;/li&gt;
&lt;li&gt;No Need to Write Unit Tests&lt;/li&gt;
&lt;li&gt;Types Are Extremely Useful&lt;/li&gt;
&lt;li&gt;Lower Tech Debt&lt;/li&gt;
&lt;li&gt;To Boldy Refactor&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Typescript?
&lt;/h2&gt;

&lt;p&gt;It is JavaScript, with optional typing, that you can refactor. The code below is both JS and TS:&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;derp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;world&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;derp&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The nice thing about TS is that I can press F2 on that &lt;code&gt;derp&lt;/code&gt; variable and rename it, and it will work even if I did it in an external module. &lt;/p&gt;

&lt;p&gt;Why is that? All thanks to the TypeScript AST produced by TS language server running under the hood inside VSCode. The collaboration between the language and the editor makes it do things that are impossible otherwise.&lt;/p&gt;

&lt;p&gt;Those who have yet to experience the joy of TypeScript, simply have yet to experience the horror of "JavaScript with friends." &lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Should I use TypeScript?
&lt;/h2&gt;

&lt;p&gt;YES.&lt;/p&gt;

&lt;p&gt;Even for a tiny little module with 1 line of code?&lt;/p&gt;

&lt;p&gt;Why YES:&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;life&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you can suffer with babel tooling, custom webpack configs, three separate rollup build configs targeting iife, cjs, esm, and heck, maybe WASM (assuming &lt;code&gt;life&lt;/code&gt; is an uint8).&lt;/p&gt;

&lt;p&gt;If not for you, think of the consumer of your module - is &lt;code&gt;life&lt;/code&gt; a string or a number? The people need to know!&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Ease of Learning.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"strict": "false"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disable strict mode, and you will be writing JavaScript. When the static compile-time warnings bother you to a certain threshold (and they should bother you), start reading into the detail as to why the warnings are as such and fix them!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you know? VSCode codebase itself was not strict until Feb, 2020 [0]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Flexible Type Checking System.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"strict": "false"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just disable strict mode, and you will wish it was slightly stricter. But 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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ApiRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/${string}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Is an example of a flexible type system, that can prevent silly mistakes across your entire codebase.&lt;/p&gt;

&lt;p&gt;The BubbleSort implemented purely using the type system [1], is also a good example of how flexible and powerful TypeScript is. Those who use it to claim TypeScript is "strict" missed the whole point of the demonstration.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Concise and Readable Syntax.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;TypeScript infers type for you:&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;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// foo is a string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you can make it do even more:&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;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="dl"&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="c1"&gt;// foo is strictly "bar"&lt;/span&gt;
&lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lol&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript self-documents its arguments. Thus you only need to document the high-level idea of your function:&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="cm"&gt;/**
 * Add two numbers
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&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="nx"&gt;b&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;add&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="nf"&gt;add&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// compile err &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Utilize it wisely, and you will have a happy little codebase.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Intuitive Syntax.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;TypeScript type syntax shares many resemblances to that of C# and C++. &lt;/p&gt;

&lt;p&gt;To the experienced, it's quite intuitive (which explains its high adoption rate). &lt;/p&gt;

&lt;p&gt;To those who are new to programming in general, the learning curve to some of the advanced syntax might be as high as learning C++ itself.&lt;/p&gt;

&lt;p&gt;This explains why Python triumphs when it comes to teaching programming - it's more intuitive to most people because there are no braces. Refactoring a large python codebase, on the other hand, is a massive chore if the tab alignment is inconsistent between modules. Jupyter notebook had made it much better over the years, tho!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Just disable strict mode, you newb! - jokingly, I said.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Modern Tooling.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;TypeScript is a compiled language. Thus, the same code can now be compiled to work on various runtimes, architectures, and systems. The drawback is, you will need to compile it OR use a runtime that runs TypeScript natively.&lt;/p&gt;

&lt;p&gt;If TypeScript does not support a certain runtime, or if the compiler is unavailable in a certain environment, it's almost trivial to add them - use &lt;code&gt;esbuild&lt;/code&gt; [2].&lt;/p&gt;

&lt;p&gt;The power of TypeScript is not about the language itself, but the result of how it is interpreted. The TypeScript AST is integrated into the TypeScript language server within the editor, which enables features such as autocompletion, module import suggestions, type inference, and cross-module refactoring. &lt;/p&gt;

&lt;p&gt;These modern tooling features might not benefit small projects as much as it does big ones. However, big project starts small, and it's better to start with the right foundation and footing, than retrospectively add them later on. &lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. High Productivity.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;Just disable strict mode, and enjoy all the speed and zero friction: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type coercion/inference&lt;/li&gt;
&lt;li&gt;Cross-module variable renaming/refactoring&lt;/li&gt;
&lt;li&gt;Import suggestion&lt;/li&gt;
&lt;li&gt;API typing and type-safe API modules&lt;/li&gt;
&lt;li&gt;Scoped variable renaming (yes, try it with plain JS)&lt;/li&gt;
&lt;li&gt;Any other TypeScript features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key productivity gained by TypeScript in an enterprise team environment is the ability to use and explore module APIs without even having to check the documentation. More so when exploring 3rd party vendor APIs.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Realistic Promises.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;Straight from the TypeScript front page:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TypeScript is JavaScript with syntax for types.&lt;br&gt;
TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It gave me exactly what it promised:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A typed language (optionally strong, just disable strict mode)&lt;/li&gt;
&lt;li&gt;Better tooling via VSCode integration, as well as tools created using and for TypeScript itself - ESBuild, PNPM, TurboRepo, etc...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Flexibility.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"strict": "false"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just disable strict mode, and you are practically writing JS, but with a &lt;code&gt;.ts&lt;/code&gt; file extension.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Large Community.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;Do you have a TypeScript question and need to speak to a community member? The TypeScript Discord server is very active: &lt;a href="https://discord.gg/typescript" rel="noopener noreferrer"&gt;https://discord.gg/typescript&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So is their Stack Overflow: &lt;a href="https://stackoverflow.com/questions/tagged/typescript" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/tagged/typescript&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the benefit of speaking a common language that's slightly more powerful (dynamic) than the base language. It's like the original British English vs. the Americanized English. The latter sees massive adoption due to its flexibility in accommodating different culture, meanwhile, the community that uses it continue to grow due to the sheer size of the continent that spawned the dialect.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Clean Code Made Easy
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;TypeScript makes it easier for the editor to understand your code - which is required for better tooling. This, in turn, promotes cleaner code. Experienced developers leverage these properties to organize their code to be maintainable and easy to refactor - for the editor and their team.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I often see inexperienced dev struggles with organizing their code because, more often than not, they tried to be "clever" with it. This happens in almost any language - C++, Python, Haskell, Scala, you name it. The elusive and novel ternary or pipe operator they recently learned often leads them to utilize it immediately - and for a good reason. That's how one learns the language syntax. This often happens because there is no clear guidance or clear-cut benefit perceived - likely, they did not use the tooling. I would argue it is much easier to write complex code that's impossible to debug in JavaScript (golf-style), than TypeScript.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  11. A JS Superset.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;TypeScript IS a JavaScript superset - just disable strict mode and ignore any compiler warning!&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;star&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trek&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;47&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code "compiles" to JS, and is also valid JS. The "superset" property of TS is that it added the TS compiler warning that tells you exactly what is wrong - the original object does not have the property "trek." The warning is a "feature" of the superset property - plain JS would not be aware of such an idea. &lt;/p&gt;

&lt;p&gt;Side note, this works:&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;star&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;trek&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;47&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  12. A Compiled Language.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&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%2F1m4jx4z545vzm97gtrf8.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%2F1m4jx4z545vzm97gtrf8.png" alt="Image description" width="461" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Being a compiled language, you can leverage the TypeScript AST to do some pretty cool stuff. Namely, you can use the latest ES syntax and let the compiler handle the compatibility for you, as well as optimization. Even better, it can target the output to node, browser, worker runtime, etc...&lt;/p&gt;

&lt;p&gt;On the other hand, you can convert the typing from other languages into TypeScript AST - from Rust to TypeScript with TypeShare for example [3]. This allows TypeScript developer to consume Rust native modules with API documentation via the Rust typing itself.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  13. Reduced Tooling.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;With the advent of parcel [4], esbuild [1], and tsup [5], you can say goodbye to extra tooling. Use one of these bundlers, and you will have TypeScript transpiling as fast as javascript being optimized by terser. This is because these bundlers skipped the type-checking steps and went straight to transpilation. &lt;/p&gt;

&lt;p&gt;This allows the editor integration to shine, and separate the linting steps from your building steps if you have a CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  14. High Performance.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;TypeScript produces much more performant code because the benefit of using it - editor integration - encourages developers to write better, cleaner code, which is easier to optimize.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  15. No Need to Write Unit Tests.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;The compiler and type system catches most of the silly mistakes possible that need to be tested with unit-test. This allows unit tests to focus on core libraries, and the team can focus on E2E test - the more important one!&lt;/p&gt;

&lt;p&gt;If you are a junior developer working under a manager who's adamant about unit tests and the 95% code coverage threshold, my condolence. You might try to convince them to disable strict mode, write your test with a TS transformer that disables strict mode, or simply write the test and add &lt;code&gt;// @ts-ignore&lt;/code&gt; at the top of the file - reap the benefit, ignore all the warning!&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  16. Types Are Extremely Useful.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;When working with other people, external APIs, and overall, any distributed system that requires you to study payloads of API that you did not own - having decent (even incomplete) types will save you $$$$ and $$$$.&lt;/p&gt;

&lt;p&gt;Try to work with the Stripe API without the typing, and deploy it to prod. &lt;/p&gt;

&lt;p&gt;I $$$$ dare you.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  17. Lower Tech Debt.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;Switching from TypeScript to Rust is a rewrite, that is not tech debt.&lt;/p&gt;

&lt;p&gt;Using plain JavaScript, with zero editor integration, resulting in inconsistent code that's impossible to refactor and maintain, is a tech debt.&lt;/p&gt;

&lt;p&gt;Arguably, you can incur tech debt by using TypeScript if you are using it without trying to utilize the benefit of the editor and tooling integration the ecosystem provides, but why would you?&lt;/p&gt;

&lt;p&gt;It's like using C++ without a linker. Now you must convert C++ to Assembly instead of writing a linker - is that a tech debt or the lack of tooling utilization? I'd argue the latter.&lt;/p&gt;

&lt;p&gt;The same can be applied to any language and ecosystem - try to use Rust without Crate, Ruby without Gem. A language represents not just its syntax, but its entire tooling ecosystem.&lt;/p&gt;

&lt;p&gt;Typescript's encouragement of clean-code erases tech debt.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  18. To Boldly Refactor.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;Finally, the key power of TypeScript, compared to plain JS or most web-based languages: is the ability to refactor a large codebase, with thousands of modules, with ease. This enables the codebase to evolve from small to medium, to large, with progression and iteration instead of a large wholesale rewrite.&lt;/p&gt;

&lt;p&gt;This would not be possible without the tight integration between TypeScript and the VSCode editor. This killer combination enables module moving, file renaming, and import resolution refactoring with a click of a button.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DID YOU KNOW? There are plenty of similar code editor enhancement solutions in other compiled language. A popular one within the C++ professional community is the Tomato kit for Visual Studio - they have provided code refactoring, renaming, etc... for C++ since 2010s [6]&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;USE TYPESCRIPT Y'ALL!&lt;/p&gt;




&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References.
&lt;/h2&gt;

&lt;p&gt;🔝 Go To TOC.&lt;/p&gt;

&lt;p&gt;[0] &lt;a href="https://code.visualstudio.com/updates/v1_43#_strict-true" rel="noopener noreferrer"&gt;https://code.visualstudio.com/updates/v1_43#_strict-true&lt;/a&gt;&lt;br&gt;
[1] &lt;a href="https://www.youtube.com/watch?v=Uf1D0GoEzlY" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=Uf1D0GoEzlY&lt;/a&gt;&lt;br&gt;
[2] &lt;a href="https://esbuild.github.io/" rel="noopener noreferrer"&gt;https://esbuild.github.io/&lt;/a&gt;&lt;br&gt;
[3] &lt;a href="https://github.com/1Password/typeshare" rel="noopener noreferrer"&gt;https://github.com/1Password/typeshare&lt;/a&gt;&lt;br&gt;
[4] &lt;a href="https://parceljs.org/" rel="noopener noreferrer"&gt;https://parceljs.org/&lt;/a&gt;&lt;br&gt;
[5] &lt;a href="https://tsup.egoist.dev/" rel="noopener noreferrer"&gt;https://tsup.egoist.dev/&lt;/a&gt;&lt;br&gt;
[6] &lt;a href="https://www.wholetomato.com/" rel="noopener noreferrer"&gt;https://www.wholetomato.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>welcome</category>
      <category>community</category>
      <category>learning</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Note about oh-my-posh, pwsh, wt + OSC99</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Thu, 01 Sep 2022 15:38:49 +0000</pubDate>
      <link>https://dev.to/louisgv/note-about-oh-my-posh-pwsh-wt-osc99-3gdf</link>
      <guid>https://dev.to/louisgv/note-about-oh-my-posh-pwsh-wt-osc99-3gdf</guid>
      <description>&lt;p&gt;When using a fancy theme in oh-my-posh, and we want to ensure the OSC99 gets registered to recall the previous PWD, make sure to fork the theme and add this to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   "pwd": "osc99"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this, osc99 will not be emitted, thus preventing Windows Terminal from restoring your session.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: This was corrected thanks to &lt;a class="mentioned-user" href="https://dev.to/jandedobbeleer"&gt;@jandedobbeleer&lt;/a&gt; (see comment section). Previously, the key and value was &lt;code&gt;"osc99": true&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ohmyposh</category>
      <category>pwsh</category>
      <category>osc99</category>
      <category>wt</category>
    </item>
    <item>
      <title>HOWTO: Injecting UI into Website with Browser Extension</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Fri, 22 Jul 2022 16:17:00 +0000</pubDate>
      <link>https://dev.to/plasmo/injecting-ui-into-website-with-browser-extension-quickly-and-safely-2o85</link>
      <guid>https://dev.to/plasmo/injecting-ui-into-website-with-browser-extension-quickly-and-safely-2o85</guid>
      <description>&lt;h2&gt;
  
  
  TL,DR:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm create plasmo inject-ui
&lt;span class="nb"&gt;cd &lt;/span&gt;inject-ui
&lt;span class="nb"&gt;touch &lt;/span&gt;content.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;content.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Overlay&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;(&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;HELLO WORLD&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;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;Overlay&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Load the extension in Chrome, refresh and you should see &lt;code&gt;HELLO WORLD&lt;/code&gt; injected into the top of the webpage.&lt;/p&gt;




&lt;h2&gt;
  
  
  Explanations
&lt;/h2&gt;

&lt;p&gt;Browser extensions can inject DOM elements into a website using a content script. However, the injected element might inherit the website's style without proper encapsulation. This is often undesirable for any site-agnostic browser extension.&lt;/p&gt;

&lt;p&gt;There are 3 solutions to the problem above:&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Render the element with a style tag that does &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/unset"&gt;css unset&lt;/a&gt;.
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;A&lt;/code&gt; is often seen employed by ad. It works well for self-contained, simple components that render images. However, it is very hard to leverage a design system that has inherited styling, since the unset cascades down. Unless you have a dedicated style injection scheme, it is very difficult to use and the extra style tag makes the code not very clean.&lt;/p&gt;

&lt;h3&gt;
  
  
  B. Render the element inside &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe"&gt;an iframe&lt;/a&gt;.
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;B&lt;/code&gt; isolates the element well and is the go-to technique of many old browser extensions. However, the iframe container can be hard to work with when trying to blend the injected component seamlessly into the website. Iframe's elements are nested inside an inner document within its frame, with its own head and body. This makes it tricky to style and control elements inside the iframe, as well as align them with the elements of the website.&lt;/p&gt;

&lt;h3&gt;
  
  
  C. Render the element inside a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM"&gt;Shadow DOM&lt;/a&gt;.
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;C&lt;/code&gt; is the best technique for web extension. Introduced as the key part of the web component API, the idea is that the shadow DOM is a separate DOM attached to the underlying main DOM. Nothing inside it can affect the main world. The Plasmo framework uses this technique behind the scene to enable seamless injection of React component into any webpage. We call this feature "content script UI."&lt;/p&gt;

</description>
      <category>extension</category>
      <category>chrome</category>
      <category>typescript</category>
      <category>plasmo</category>
    </item>
    <item>
      <title>HOWTO: Consuming CJS in a Typescript module</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Wed, 26 Jan 2022 12:36:00 +0000</pubDate>
      <link>https://dev.to/plasmo/consuming-cjs-in-a-typescript-module-5402</link>
      <guid>https://dev.to/plasmo/consuming-cjs-in-a-typescript-module-5402</guid>
      <description>&lt;p&gt;At &lt;a href="https://www.plasmo.com/"&gt;Plasmo&lt;/a&gt; we leverage Typescript for our web projects.&lt;br&gt;
CJS project like &lt;a href="https://github.com/ralyodio/humanparser"&gt;humanparser&lt;/a&gt; would have example like this:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;human&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;humanparser&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;fullName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mr. William R. Hearst, III&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;attrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;human&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parseName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fullName&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;require&lt;/code&gt; statement is how we import the &lt;code&gt;humanparser&lt;/code&gt; module into a CJS codebase. This statement can be translated into TypeScript/ESM 2 ways:&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;humanParser&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;humanparser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OR&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="nx"&gt;humanParser&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;humanparser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Which is it?
&lt;/h2&gt;

&lt;p&gt;The answer lies in the source code of the &lt;code&gt;humanparser&lt;/code&gt; module itself. This is an artifact from the evolution of ES, from ES3-&amp;gt; ES5 -&amp;gt; ES6 and beyond (now ESM). There were a couple of ways a module could be exported. &lt;/p&gt;

&lt;p&gt;The first, commonly used during the transition between ES3 -&amp;gt; ES5 (early nodejs days), was to assign an entry function or object into &lt;code&gt;module.exports&lt;/code&gt; global:&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stuff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;module.exports&lt;/code&gt; global was used to bridge into the &lt;code&gt;require&lt;/code&gt; statement. Because &lt;code&gt;module.exports&lt;/code&gt;  represent "everything" that was exported from this module, we must use the import all statement:&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;humanParser&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;humanparser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;*&lt;/code&gt; represents the &lt;code&gt;module.exports&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Another way, which occurred during the transition between ES5-&amp;gt;ES6, is to export a &lt;code&gt;default&lt;/code&gt; property as the entry for your module:&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stuff&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This assigned &lt;code&gt;stuff&lt;/code&gt; into the &lt;code&gt;defaults&lt;/code&gt; property exported by the module. The reason why this was done is because in ES6, when doing:&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="nx"&gt;humanParser&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;humanparser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code is actually importing the &lt;code&gt;default&lt;/code&gt; props exported by a module. (The export statement in ES6 would be: &lt;code&gt;export default stuff&lt;/code&gt;). The import statement above is doing something like this in equivalent CJS code:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;humanParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;humanparser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, back to &lt;code&gt;humanparser&lt;/code&gt;'s source code, their export statement looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const parser = module.exports = {};
parser.parseName = function(){}
parser.getFullestName = (str) =&amp;gt; {}
parser.parseAddress = (str) =&amp;gt; {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because there's no &lt;code&gt;default&lt;/code&gt; prop being exported, we can import the parser two ways, either importing the whole object:&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;humanparser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OR, importing the props that was exported separately:&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;parseName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parseAddress&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="s2"&gt;humanparser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Personally, I like to import the named export, it helps with code intelligent, and I don't have to deal with the import all module namespace issue.&lt;/p&gt;




&lt;h2&gt;
  
  
  Back Story
&lt;/h2&gt;

&lt;p&gt;Back in the olden day, pre-2015 to be exact, where angular.js were still trendy, react was still the new kid in the block, and people were comparing Corodva phonegap to react native, there was a transition from ES3/ES5 (commonJS or CJS) to ES6 (ES2015, or ESM, or MJS - modulejs). I suspect whoever named the extension was a huge fan of the late pop king.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cautions
&lt;/h2&gt;

&lt;p&gt;If you are looking at new projects, be cautious of pure ESM module. They will only allow you to import them with:&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="nx"&gt;mod&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tricky part is that, your project must also be a module - i.e, it cannot be compiled into common js (which converted all &lt;code&gt;import&lt;/code&gt; statement into cjs &lt;code&gt;require&lt;/code&gt; call). It must be an MJS/ecmascript module file (with the .mjs extension) OR that your &lt;code&gt;package.json&lt;/code&gt; have specified the module property. Otherwise, it would simply fail to compile, and you won't be able to import it using require because ESM code looks 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="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;stuff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of this:&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stuff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the CJS example, &lt;code&gt;module.exports&lt;/code&gt; are bridged into the &lt;code&gt;require&lt;/code&gt; statement for importing in other modules. Meanwhile, in the ESM example, the &lt;code&gt;stuff&lt;/code&gt; is being exported by the &lt;code&gt;export&lt;/code&gt; statement , and thus can only be imported via the import statement.&lt;/p&gt;

&lt;p&gt;The dilemma here is that if you're using TypeScript and was hoping that it would play well with ESM only module, you are in for some sour candy - it does not. Typescript compiler doesn't yet care if a module it imported is ESM or not -  it converts all to CJS import unless you configured it properly. You would also need to tell nodejs to use an experimental flag when running your compiled code: &lt;a href="https://nodejs.org/api/esm.html#customizing-esm-specifier-resolution-algorithm"&gt;https://nodejs.org/api/esm.html#customizing-esm-specifier-resolution-algorithm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;P.s: this post is a brain-dump. If it's useful, you're welcome. If not, here's the MIT license for this otherwise unreadable post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Copyright 2022 L❤☮🤚

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

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

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Notes on default ES behavior</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Tue, 07 Dec 2021 06:48:26 +0000</pubDate>
      <link>https://dev.to/louisgv/notes-on-default-es-behavior-33ia</link>
      <guid>https://dev.to/louisgv/notes-on-default-es-behavior-33ia</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const n = null

console.log(n?.something) // undefined

const o = {}

console.log(o?.something) // undefined

function test(d = 0) {
    console.log({ d })
}

test(o?.something) // { d : 0 }
test(n?.something) // { d : 0 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>programming</category>
      <category>notes</category>
    </item>
    <item>
      <title>Undocumented EAS flag in Expo SDK 43</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Mon, 22 Nov 2021 03:47:54 +0000</pubDate>
      <link>https://dev.to/louisgv/undocumented-eas-flag-in-expo-sdk-43-4d7h</link>
      <guid>https://dev.to/louisgv/undocumented-eas-flag-in-expo-sdk-43-4d7h</guid>
      <description>&lt;p&gt;I was working on deploying &lt;a href="https://www.pondercoach.com"&gt;ponder&lt;/a&gt;'s native app to TestFlight using &lt;a href="https://expo.dev/eas"&gt;Expo EAS&lt;/a&gt; when I found some interesting undocumented EAS feature flags that I think folks should know. These are especially useful if you have a monorepo.&lt;/p&gt;

&lt;p&gt;First, I just wanted to say thank you to the &lt;a href="https://expo.dev/"&gt;Expo team&lt;/a&gt; for making native deployment a breeze. And the fact that their source code is open really help resource-constrained team (like mine) to solve our own problem and get stuffs done without having to wait for their next release.&lt;/p&gt;

&lt;p&gt;When using &lt;code&gt;eas build&lt;/code&gt;, the &lt;code&gt;eas-cli&lt;/code&gt; first create an artifact of the project's source code, before pushing to the cloud for remote building. The default behavior is to &lt;a href="https://github.com/expo/eas-cli/blob/dddc4a0e95650254def3ec2fc45af4bcfab412be/packages/eas-cli/src/vcs/clients/git.ts#L73-L119"&gt;use git as a source of truth to generate the latest source code artifact&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, if the monorepo contains server-side module or any code unrelated to the expo project, it would also be included in the uploaded artifact. This results in an additional security risk - i.e if expo's artifact storage were to be compromised, our internal business logic will be exposed.&lt;/p&gt;

&lt;p&gt;At the moment, the default git workflow does not provide a way to ignore file during the artifact creation process (since it's just invoking git internally). Thankfully, as of Expo SDK 43, a new flag &lt;code&gt;EAS_NO_VCS=1&lt;/code&gt; was introduced to &lt;a href="https://github.com/expo/fyi/blob/master/eas-build-archive.md#how-do-i-opt-out-of-using-git"&gt;opt-out of using git or any VCS&lt;/a&gt; to create the artifact using &lt;a href="https://github.com/expo/eas-cli/blob/dddc4a0e95650254def3ec2fc45af4bcfab412be/packages/eas-cli/src/vcs/local.ts#L73-L84"&gt;shallow file copy&lt;/a&gt;. With this flag, EAS then read from an &lt;code&gt;.easignore&lt;/code&gt; file to determine which file it should not copy into the cloud build artifact. The syntax for the &lt;code&gt;.easignore&lt;/code&gt; file is the same as a &lt;code&gt;.gitignore&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# add any modules in your monorepo that is unrelated to EAS
service-a/
server-b/
socket-c/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, there's one issue: &lt;code&gt;monorepo&lt;/code&gt;. In git workflow, expo can simply rely on git to get the project structure. With the plain workflow, expo can now only see the current directory it is running in. Thankfully, the expo team had implemented a solution for this, albeit undocumented.&lt;/p&gt;

&lt;p&gt;I found this solution while reading through &lt;a href="https://github.com/expo/eas-cli/"&gt;&lt;code&gt;eas-cli&lt;/code&gt;&lt;/a&gt; source code, looking for a way to patch it. Apparently, &lt;code&gt;eas-cli&lt;/code&gt; also read another flag in the environment called &lt;code&gt;EAS_PROJECT_ROOT&lt;/code&gt;: &lt;a href="https://github.com/expo/eas-cli/blob/dddc4a0e95650254def3ec2fc45af4bcfab412be/packages/eas-cli/src/vcs/local.ts#L14-L20"&gt;source&lt;/a&gt;. This variable is used by the EAS shallow copy method to create the complete project artifact.&lt;/p&gt;

&lt;p&gt;To use this flag, first I move my &lt;code&gt;.easignore&lt;/code&gt; file to the root of my monorepo. Then, I run EAS like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;cross-env EAS_NO_VCS=1 EAS_PROJECT_ROOT=.. eas build&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And voila - everything worked. Now instead of uploading a whooping 160MB artifact, our deployment upload a measly 2.6MB artifact of front-end specific code!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>expo</category>
      <category>eas</category>
      <category>opensource</category>
    </item>
    <item>
      <title>TypeScript Dynamic Module Import</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Mon, 22 Nov 2021 00:43:00 +0000</pubDate>
      <link>https://dev.to/louisgv/typescript-dynamic-module-import-2dln</link>
      <guid>https://dev.to/louisgv/typescript-dynamic-module-import-2dln</guid>
      <description>&lt;p&gt;Can you tell the difference between these two import statements?&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="nx"&gt;Button&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@kenaz/button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VS&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;buttonModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@kenaz/button&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;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buttonModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple right? - The first imports the module statically at &lt;code&gt;build-time&lt;/code&gt;, whereas the second imports the module dynamically at &lt;code&gt;run-time&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;With the first code snippet, most ES bundler will include the button component in our final bundle. Whereas with the second snippet, our button could be split into a separate chunk. This could be an advantage when your page gets super duper complex with 1000 states, but the button is only needed in 1 of those states.&lt;/p&gt;

&lt;p&gt;Now, can you tell the difference between these twos?&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;loadButton&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;buttonModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@kenaz/button&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="nx"&gt;buttonModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&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;VS&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;loadComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@kenaz/button&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="kr"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&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;Disregard the context and the use case supplied via the naming of those functions, these two dynamic import statements do not seem to differ that much. At least, that's what I thought when I was using these two interchangeably while developing locally with a dev server that was transpiling these code on-the-fly. &lt;/p&gt;

&lt;p&gt;However, the difference came to light when I created a production bundle while trying to import a local module using the 2nd snippet:&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;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;loadComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It threw this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cannot find module './button'
Require stack:

/app/dist/index.js Error: Cannot find module './button'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;I filed an &lt;a href="https://github.com/vercel/ncc/issues/793"&gt;issue&lt;/a&gt; for the &lt;code&gt;ncc&lt;/code&gt; bundler regarding a similar behavior&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It turned out that when passing a local path to &lt;code&gt;import&lt;/code&gt;, the code becomes unanalyzable by the TypeScript compiler. Thus, the compiler does not bundle the local import code, leaving us with the error above.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The more I think of this, the more I realized this behavior is reasonable. I.e, if the module name is arbitrary, how could the compiler know which module would be imported? Should it just compile every possible combination of file in the project then? That's probably not a good solution...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My conclusion: for local module (owned by my project such as &lt;code&gt;"./button"&lt;/code&gt;), statically analyzable dynamic import is required for most bundler to find and compile those module correctly. On the other hand, if the module is in a separate module (a dependency such as &lt;code&gt;@org/some-module&lt;/code&gt;), the node runtime can crawl the &lt;code&gt;node_packages&lt;/code&gt; directory for them.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>architecture</category>
      <category>node</category>
    </item>
    <item>
      <title>Quick guide to AudioWorklet 🔉</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Fri, 05 Nov 2021 19:17:09 +0000</pubDate>
      <link>https://dev.to/louisgv/quick-guide-to-audioworklet-30df</link>
      <guid>https://dev.to/louisgv/quick-guide-to-audioworklet-30df</guid>
      <description>&lt;p&gt;&lt;a href="https://www.pondercoach.com/" rel="noopener noreferrer"&gt;Ponder&lt;/a&gt; is a voice-first application with audio recording and processing as its core features. Unlike most audio Web Apps where the processing is done after the recording is finished, Ponder processes the audio in real-time to provide advanced business logic and features such as transcription. There are two requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Storing audio with full integrity and cross-device playback&lt;/li&gt;
&lt;li&gt;Processing the audio while recording in real-time&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This article is a guide to how Ponder accomplishes these requirements using AudioWorklet.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐞 The problem with ScriptProcessor
&lt;/h2&gt;

&lt;p&gt;The WebAudio ScriptProcessor API was deprecated in favor of the AudioWorklet in 2014. However, the AudioWorklet API was unavailable on iOS Safari until the recent 15.0 update.&lt;/p&gt;

&lt;p&gt;Over six months of beta testing our product, we received feedback from our customers with concerns about the recorded audio quality when using Safari on iOS.&lt;/p&gt;

&lt;p&gt;We investigated two solutions to mitigate the issue:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Splitting the audio stream using two separate ScriptProcessor nodes:

&lt;ul&gt;
&lt;li&gt;Node A with a buffer rate of 8192 for smoother audio playback&lt;/li&gt;
&lt;li&gt;Node B with a buffer rate of 4096 for frequent transcription requests&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Using a WebWorker to process the audio buffer in a background thread, using &lt;a href="https://github.com/GoogleChromeLabs/comlink" rel="noopener noreferrer"&gt;GoogleChromeLabs/comlink&lt;/a&gt; and &lt;a href="https://github.com/GoogleChromeLabs/worker-plugin" rel="noopener noreferrer"&gt;GoogleChromeLabs/worker-plugin&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52qgrofh1qvv1q1xqud9.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52qgrofh1qvv1q1xqud9.png" alt="Audio stream splitting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The audio stream splitting method was a neat technique that helped with optimizing our audio processing pipeline, and the WebWorker processor setup, with full TypeScript interop through comlink, was a breeze to work with.&lt;/p&gt;

&lt;p&gt;The resulting code was concise and pretty, but it did not solve the audio problem. If anything, these improvements made our system even more fragile. On Android, the audio worked well. On iOS however, the audio suffered issues from lagging to stuttering, to missing a large chunk of recorded audio. We observed an improvement to the smoothness of our UI, however our priority is the quality and integrity of the audio.&lt;/p&gt;

&lt;p&gt;From a first principle perspective, the audio buffer that we were getting data from is still being generated by the ScriptProcessor API's callback. This led us to conclude that it would likely remain until we replaced the ScriptProcessor API.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐴 ScriptProcessor implementation
&lt;/h2&gt;

&lt;p&gt;We initially used the approach described in &lt;a href="https://web.archive.org/web/20210829201843/https://developers.google.com/web/fundamentals/media/recording-audio/#access_the_raw_data_from_the_microphone" rel="noopener noreferrer"&gt;this google documentation&lt;/a&gt; for our old ScriptProcessor based audio recorder.&lt;/p&gt;

&lt;p&gt;Below is the most relevant code snippet inspired by that tutorial:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffv9dd5vdyk552gdj278r.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffv9dd5vdyk552gdj278r.png" alt="ScriptProcessor Code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🦄 AudioWorklet implementation
&lt;/h2&gt;

&lt;p&gt;In this section, we shall implement an in-place replacement for the above ScriptProcessor code, using the AudioWorkletProcessor API. The two key code paths were marked &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A: Replace ScriptProcessor with an implementation using AudioWorkletProcessor&lt;/li&gt;
&lt;li&gt;B: Get the data from AudioWorkletProcessor and consume it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A: Replacing ScriptProcessor
&lt;/h3&gt;

&lt;p&gt;First, let's create a &lt;code&gt;recorder.worklet.js&lt;/code&gt; file for our &lt;code&gt;AudioWorkletProcessor&lt;/code&gt;:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgis7kf79mconiqwzff35.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgis7kf79mconiqwzff35.png" alt="First AudioWorkletProcessor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This file should be served by your static web server. In a &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;nextjs&lt;/a&gt; application, you can simply place it under the &lt;code&gt;public&lt;/code&gt; directory. Then, in your web app, register the Worklet processor as follows:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frm2l5yetmugqrzxzdm4v.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frm2l5yetmugqrzxzdm4v.png" alt="Register Worklet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  B: Reimplementing ScriptProcessor
&lt;/h3&gt;

&lt;p&gt;Currently, the &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; emit audio data blocks of 128 frames long - i.e a Float32Array of 128 data sample &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/AudioWorkletProcessor/process" rel="noopener noreferrer"&gt;doc📄&lt;/a&gt;. To emulate the behavior of &lt;code&gt;ScriptProcessor&lt;/code&gt;, we will need to buffer the sample data produced by &lt;code&gt;AudioWorkletProcessor&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While researching this setup, I stumbled upon a helpful &lt;a href="https://gist.github.com/flpvsk/047140b31c968001dc563998f7440cc1" rel="noopener noreferrer"&gt;gist&lt;/a&gt; by &lt;a href="https://github.com/flpvsk" rel="noopener noreferrer"&gt;flpvsk&lt;/a&gt;. The buffer implementation below borrowed many ideas from that gist.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Buffering&lt;/strong&gt; is a technique in data processing where instead of consuming the input data right away, we store the data in a temporary location and wait until a certain threshold is met to start reading the data. The key use case is when the input is a stream of data, and the output is a decoded representation of the streamed data, such as audio and video.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do we need buffering?&lt;/strong&gt; - Let’s take a look at a communication example: Alice is sending Bob a sequence of letters: H, E, L, L, O. If Bob’s short term memory was not functioning, he might have forgotten about the letter H the moment he received the letter E, and so on and so forth. Thus, the lack of buffering prevented Bob from forming a coherent word from Alice, leading to miscommunication. If his memory is normal, he would buffer the letters until his brain recognizes that a group of letters matches a word in his vocabulary.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8o07hi75l4jhdccmindv.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8o07hi75l4jhdccmindv.png" alt="Alice and bob"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea is similar when processing microphone input for human speech. The basic groundwork to set up a buffer requires 3 fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;bufferSize&lt;/strong&gt;: A variable to track the size of the buffer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;_byteWritten&lt;/strong&gt;: A pointer to track the location of the last byte written (i.e, an index)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;_buffer&lt;/strong&gt;: The buffer itself&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fneefts1i86t4hf18h9q9.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fneefts1i86t4hf18h9q9.png" alt="Basic buffer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To capture the &lt;code&gt;Float32Array&lt;/code&gt; of data samples produced by &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; mentioned earlier, we implement its &lt;code&gt;process&lt;/code&gt; method and store the data as follows:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1w3ey8e6e7kzhx76hwz.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1w3ey8e6e7kzhx76hwz.png" alt="Capture buffer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;append&lt;/code&gt; method above allows us to fill the data buffer with microphone samples. Next, we will need to check if the buffer is full to emit the data back to our main thread for upstream processing. We will also want to reset the &lt;code&gt;_bytesWritten&lt;/code&gt; pointer. Let's call this operation &lt;code&gt;flush&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To make it easier to work with our buffer and implement &lt;code&gt;flush&lt;/code&gt;, we can add a couple of helper methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;initBuffer&lt;/strong&gt;: Reset our _byteWritten pointer to its initial position&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;isBufferEmpty&lt;/strong&gt;: Check if our pointer is at its initial position&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;isBufferFull&lt;/strong&gt;: Check if our pointer is of the same size as our pre-allocated buffer&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0tzrbcvybak1hpy0whi.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0tzrbcvybak1hpy0whi.png" alt="Helpers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With our helpers, we can implement &lt;code&gt;flush&lt;/code&gt; method as follows:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7sipi7kpy36ynxa9qhp.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7sipi7kpy36ynxa9qhp.png" alt="Flush method"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we can invoke this &lt;code&gt;flush&lt;/code&gt; method at the beginning of our &lt;code&gt;append&lt;/code&gt; like so:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvgtw1vdo3o4geadcmcy.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvgtw1vdo3o4geadcmcy.png" alt="invoke flush"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With that, our re-implementation of the &lt;code&gt;ScriptProcessor&lt;/code&gt; node with a 4096 buffer size and a single input/output channel is now complete. The full code is published &lt;a href="https://gist.github.com/louisgv/f210a1139d955baf511ff35f58fc8db1" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, you can retrieve the data and consume it the same way you would with &lt;code&gt;ScriptProcessor&lt;/code&gt; in your web app:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4qmtzwu8g8flrkj9nv9.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4qmtzwu8g8flrkj9nv9.png" alt="Get F32 data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: GCP's speech to text service requires an &lt;code&gt;Int16Array&lt;/code&gt; buffer. An example utility to convert the &lt;code&gt;Float32Array&lt;/code&gt; is shown below:&lt;/p&gt;
&lt;/blockquote&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fso2sssqg5edenh77zwcl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fso2sssqg5edenh77zwcl.png" alt="convert F32 to I16"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have any questions or feedback? Feel free to leave a comment here or on the &lt;a href="https://gist.github.com/louisgv/f210a1139d955baf511ff35f58fc8db1" rel="noopener noreferrer"&gt;gist&lt;/a&gt; itself!&lt;/p&gt;

&lt;h2&gt;
  
  
  🧪 Why did we choose a buffer size of 4096?
&lt;/h2&gt;

&lt;p&gt;Recall our buffering example above: the buffer size in that example is a single alphabet letter. For speech audio communication however, there is no direct equivalent. Thus, we need to experiment with the delay in real-time transcription responses coming from &lt;a href="https://cloud.google.com/speech-to-text" rel="noopener noreferrer"&gt;Google Speech to Text service&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A smaller buffer size results in more frequent invocation of the &lt;code&gt;flush&lt;/code&gt; method, and vice versa. Flush effectively sends data to the speech service.&lt;/p&gt;

&lt;p&gt;For our experimentation, we track 2 timestamps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Time when flush was first called&lt;/li&gt;
&lt;li&gt;Time when our client received the first transcribed word&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By subtracting t1 from t2, we can obtain the total delay:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fan4ah7ydxuvqne7cht9a.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fan4ah7ydxuvqne7cht9a.png" alt="Delay calculation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AudioWorklet emits a minimum of 128 bytes per tick. Following ScriptProcessor's &lt;a href="https://web.archive.org/web/20211019021407/https://developer.mozilla.org/en-US/docs/Web/API/ScriptProcessorNode" rel="noopener noreferrer"&gt;implementation&lt;/a&gt;, our buffer size should be a power of 2 between 128 and 16384. For each size, we repeat the experimentation 10 times. The results are in the table below:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpracurlocdro8y6qov27.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpracurlocdro8y6qov27.png" alt="buffer size data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To analyze the data, we can visualize it with a box plot:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzerd0xzhpklqf1ihrzyn.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzerd0xzhpklqf1ihrzyn.png" alt="Buffer size box plot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on the plot, 4096 was chosen since it has the lowest delay, while also having a reasonable buffer size to reduce processing frequency.&lt;/p&gt;

&lt;p&gt;After switching to our new &lt;code&gt;AudioWorklet&lt;/code&gt; implementation, Ponder has stopped seeing audio quality issues such as lagging, stuttering, or missing audio. Furthermore, the transcription speed is noticeably faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  🙏 Thank you to our beta testers!
&lt;/h2&gt;

&lt;p&gt;This post is dedicated to the constructive feedback that motivated our engineering team to keep on improving Ponder's asynchronous coaching experience. The architecture improvement detailed in this post is now on our staging environment and is being tested by our internal team. We will release it into production under &lt;a href="https://my.ponder.coach" rel="noopener noreferrer"&gt;Ponder &lt;strong&gt;v1.5.0&lt;/strong&gt;&lt;/a&gt;. Stay tuned!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webaudio</category>
      <category>audioworklet</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>typescript and create-react-app .env</title>
      <dc:creator>Louis</dc:creator>
      <pubDate>Tue, 06 Aug 2019 14:50:43 +0000</pubDate>
      <link>https://dev.to/louisgv/typescript-and-create-react-app-env-136e</link>
      <guid>https://dev.to/louisgv/typescript-and-create-react-app-env-136e</guid>
      <description>&lt;p&gt;You can create a type definition file that extends the NodeJS namespace to enable auto-completion for your env configuration. This is quite useful if you plan to reduce the amount of time spent looking up your &lt;code&gt;.env&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3U_LUBUM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/o60b5slh7kjjbp852694.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3U_LUBUM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/o60b5slh7kjjbp852694.png" alt="Auto Completion for your process.env!" width="461" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check bottom for the solution. For now, let’s wander back a bit. I first thought about this problem when I found that &lt;code&gt;process.env.NODE_ENV&lt;/code&gt; is typed and has code completion, while the other does not:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5px-c_5I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/33j0d4duki9z6n66axa7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5px-c_5I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/33j0d4duki9z6n66axa7.png" alt="NODE_ENV has code completion." width="462" height="58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This piece of information had been in my mind since the first time I saw it around 2017. However, I never really looked into it too deeply as back then I had no need to leverage client-side environment variable.&lt;/p&gt;

&lt;p&gt;At &lt;a href="//www.plasmo.com"&gt;Plasmo&lt;/a&gt;, we decided to leverage client-side environment to swap between staging and production endpoints. Initially with 2 variables it was manageable. But when that number grew to 13, it became a bit annoying to lookup the .env file, as the variable names are increasingly getting longer. This annoyance can be tolerated for a while, as we were focusing on our product. However, in the back of my mind, there was a strong drive to squash this “bug.”&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Technically this is not a bug, that is why there were "”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A big win of using TypeScript is that refactoring is a breeze, and that is the key to move fast — starting with one file, grow it to 300 loc, then split it into several files, rinse repeat. This applies to our type definition as well, as using a single &lt;code&gt;.d&lt;/code&gt; (definition) file to describe both our api typing as well as our theme typing becomes convoluted. So we decided to finally split our typing into these neat files:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ihqCx_Fq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/78a4prz5x09tapw7qemn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ihqCx_Fq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/78a4prz5x09tapw7qemn.png" alt="typings" width="231" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, I can bid our good ol’ &lt;code&gt;react-app-env.d.ts&lt;/code&gt; farewell. But much to my surprise, when resuming CRA (create-react-app) server afterward, that file was resurrected. After going through CRA's internal packages for a bit, I found that react-scripts (the main program powering CRA) was programmed to generate this file.&lt;/p&gt;

&lt;p&gt;This is when my brain started to notice the name of this file: &lt;code&gt;react-app-env&lt;/code&gt;. Every magic string has meaning, said the basic rule of edb (on Windows you can use x64dbg). To generate a file with such specific name means there was some significant use of it, probably within the organization of &lt;code&gt;${process.env.REACT_APP_AUTHOR}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Digging deeper with &lt;a href="//duckduckgo.com"&gt;duckduckgo.com&lt;/a&gt; with the search term “react-app-env.d.ts declare global,” the &lt;a href="https://github.com/facebook/create-react-app/issues/5576"&gt;third result&lt;/a&gt; (note: not 1st or 2nd, but 3rd) gave some great insight, in particular, &lt;a href="https://github.com/facebook/create-react-app/issues/5576#issuecomment-433613637"&gt;in this comment&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mBjfrYdU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/09la585qu012i0okbmgm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mBjfrYdU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/09la585qu012i0okbmgm.png" alt="In case the github link got spike traffic&amp;lt;br&amp;gt;
" width="700" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The github issue's author was trying to tackle the “bug” at hand, and the code snippet was extremely insightful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;declare namespace NodeJS {
  interface ProcessEnv {
    NODE_ENV: 'development' | 'production' | 'test'
    PUBLIC_URL: string
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In brief, the typescripts support of CRA consume an extended definition under the NodeJS namespace. To extend it for our environment, simply put the snippet above in your &lt;code&gt;react-app-env.d.ts&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  BONUS
&lt;/h1&gt;

&lt;p&gt;You now know how to extends your environment typing for some good old lazy &lt;code&gt;process.env&lt;/code&gt; auto-completion. But now you need to deal with global API placed under Window (like Stripe.js). Below will save you a trip to the duck (This is a simplified version of our &lt;code&gt;react-app-env.d.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// &amp;lt;reference types="react-scripts" /&amp;gt;
declare namespace NodeJS {
interface ProcessEnv {
    NODE_ENV: 'development' | 'production' | 'test'
    PUBLIC_URL: string
    REACT_APP_HASH: string
    REACT_APP_API_URI: string
    REACT_APP_WS_URI: string
    }
}
interface Window {
    Stripe: any
}

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

&lt;/div&gt;



</description>
      <category>react</category>
      <category>typescript</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
