<?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: Zach</title>
    <description>The latest articles on DEV Community by Zach (@zacharylee).</description>
    <link>https://dev.to/zacharylee</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1453981%2F914dd71f-2f46-4a0f-9e5f-67613437d5c8.png</url>
      <title>DEV Community: Zach</title>
      <link>https://dev.to/zacharylee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zacharylee"/>
    <language>en</language>
    <item>
      <title>How AI changed the way I pick frameworks, and the two places React survived</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Tue, 21 Jul 2026 00:51:32 +0000</pubDate>
      <link>https://dev.to/zacharylee/how-ai-changed-the-way-i-pick-frameworks-and-the-two-places-react-survived-3h3</link>
      <guid>https://dev.to/zacharylee/how-ai-changed-the-way-i-pick-frameworks-and-the-two-places-react-survived-3h3</guid>
      <description>&lt;p&gt;That 130-file PR that shipped KeyEcho 1.0 contained a decision I never wrote about: the desktop app moved from Tauri 1 + Vue to Tauri 2 + SolidJS.&lt;/p&gt;

&lt;p&gt;The same summer, upweb.dev moved from Nuxt 4 to SolidStart, and keyecho.app (SSR, five languages, Stripe checkout) was built on SolidStart from scratch. Three separate decisions, same answer every time.&lt;/p&gt;

&lt;p&gt;Scope first. This post is about defaults for my personal projects. Near the end I'll cover two places where I still use React, one of which runs very well.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The criteria changed&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Most of the code in my repos is AI-generated now. My job has shifted from writing code to reviewing it.&lt;/p&gt;

&lt;p&gt;The old framework checklist put most of its weight on learning curve and developer experience. Both are worth zero now: the model writes five frameworks fluently and knows the rules of hooks better than most humans do. AI crushed the price of writing code. Two costs didn't move: the runtime bytes every user downloads, and the human hours spent reviewing. Pick your stack by the new prices.&lt;/p&gt;

&lt;p&gt;Runtime cost lives in the architecture. No prompt removes it, so it decides the framework. Review bandwidth is finite, and AI throughput will grind down any consistency that is maintained by verbal agreement, so it decides the styling layer. I have seen more than one React codebase a few years into its life: two animation libraries, two carousel components, three styling systems, each introduced for a perfectly good reason on some ticket, and the sum is a mess nobody can clean up. AI did not invent that drift. It made it an order of magnitude faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;React is no longer my default: size and performance&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let me discard the weak arguments first. Dependency arrays, stale closures, re-render storms: I am not going to relitigate any of it. The model knows the rules of hooks cold, eslint-plugin-react-hooks catches most slips, and React Compiler now handles memoization. The ergonomics debate no longer produces a winner.&lt;/p&gt;

&lt;p&gt;What still produces a winner is the client. react-dom is roughly 40 kB compressed, a virtual DOM plus a reconciler, downloaded, parsed, and executed on every cold visit by every user. React Compiler can remove wasted re-renders. It cannot remove the runtime itself. Developers never feel this cost. Users on phones pay it constantly.&lt;/p&gt;

&lt;p&gt;My projects are one person plus a fleet of agents. Hiring pools do not help me, and content sites barely touch the component-library ecosystem. Once the weights shift like that, React has no slot left in my personal stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The same app, written ten times&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Loren Stewart ran an experiment last year: the same kanban app implemented in ten frameworks, identical features (drag and drop, comments, tags, server validation), then compared compressed JS on the board page.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Framework&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Compressed JS&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Next.js 16 (React 19)&lt;/td&gt;
&lt;td&gt;176.1 kB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TanStack Start (React 19)&lt;/td&gt;
&lt;td&gt;118.2 kB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Analog (Angular 20)&lt;/td&gt;
&lt;td&gt;103.9 kB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nuxt 4 (Vue 3)&lt;/td&gt;
&lt;td&gt;74.7 kB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TanStack Start + Solid&lt;/td&gt;
&lt;td&gt;60.4 kB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwik City&lt;/td&gt;
&lt;td&gt;58.4 kB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SvelteKit (Svelte 5)&lt;/td&gt;
&lt;td&gt;54.1 kB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SolidStart (SolidJS 1.9)&lt;/td&gt;
&lt;td&gt;41.5 kB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Astro + HTMX&lt;/td&gt;
&lt;td&gt;34.3 kB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Marko&lt;/td&gt;
&lt;td&gt;28.8 kB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two comparisons stand out. Same meta-framework, TanStack Start, with React swapped for Solid: 118.2 kB becomes 60.4 kB. Next.js against SolidStart: a 4.2x gap. His conclusion was that React's architectural cost is something no meta-framework can optimize away.&lt;/p&gt;

&lt;p&gt;The boundaries, as always. All ten implementations had FCP between 35 and 71 ms, indistinguishable by feel. Real-site bottlenecks are usually images and video, and framework JS is a small share of total bytes. But the two costs behave differently: media optimization is ongoing labor for the life of the site, while framework weight is fixed forever at &lt;code&gt;pnpm create&lt;/code&gt;. AI already flattened the cost of writing the code. For the same feature set, there is no reason to start four times heavier.&lt;/p&gt;

&lt;p&gt;First-party numbers, same site, before and after. On Nuxt 4, upweb.dev scored 70/100/100/100 on mobile PageSpeed. I did round after round of tuning at the Cloudflare layer and the performance score would not move; the lab bottleneck kept pointing at JS weight. After the move to SolidStart: 99/100/100/100, simulated Moto G Power on slow 4G, FCP 1.5 s, LCP 1.8 s, CLS 0.006, TBT 0 ms. That zero TBT is where fine-grained reactivity pays off most: there is no virtual tree to reconcile on the main thread.&lt;/p&gt;

&lt;p&gt;Squeeze the water out of this comparison before quoting it: Lighthouse lab data, a single-page session, a sample of one site, and the framework was not the only variable. People will remind you that lab scores are not real user experience, and they are right. RUM tells you how users are doing today; the lab tells you how much headroom the architecture leaves. Same domain, same CDN config, framework swapped, and the score went from 70 to 99. Free points. I took them.&lt;/p&gt;

&lt;p&gt;Desktop follows the same logic: inside a Tauri WebView, every kilobyte shaved off the runtime comes back as cold-start time and memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;I did look at Svelte, Vue, Qwik, and Marko&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Svelte 5's runes are signals too, and SvelteKit's 54.1 kB is small enough. Vue's reactivity comes from the same family, and Nuxt's 74.7 kB is the best result among the big-three meta-frameworks. What ruled them out is the language layer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.svelte&lt;/code&gt; and &lt;code&gt;.vue&lt;/code&gt; are custom file formats. TypeScript is one region inside the file, and type checking runs through a bridge: svelte-language-tools on one side, Volar on the other. The bridge works fine day to day. The bill arrives when the toolchain moves. TypeScript 7.0 went GA on the 8th of this month, a native Go compiler, officially about 10x faster, with type-checking of the VS Code codebase dropping from 125.7 seconds to 10.6. JSX is plain TS, so a Solid project switches the day it ships, zero changes. The compiler API that Vue and Svelte template checking depends on has no stable version in 7.0. They wait for 7.1 in October. Every extra language layer is another place in the upgrade queue.&lt;/p&gt;

&lt;p&gt;One more against Nuxt: streaming SSR is still locked behind the experimental &lt;code&gt;ssrStreaming&lt;/code&gt; flag, while streaming in SolidStart is one of &lt;code&gt;createHandler&lt;/code&gt;'s three built-in rendering modes. No flag to flip.&lt;/p&gt;

&lt;p&gt;Qwik's resumability solves huge, interaction-sparse landing pages, which my sites are not, and I did not want to carry its mental model. Marko's 28.8 kB is the smallest of the ten, but the ecosystem is too small a bet for two sites I plan to maintain for years.&lt;/p&gt;

&lt;p&gt;Reactivity models have been converging. Vue refs, Svelte 5 runes, Angular and Preact signals, plus the TC39 Signals proposal, all point the same way. React is the lone exception, patching around it with a compiler. Signals, JSX, plain TS: ask for all three at once and Solid is what is left.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Astro is smaller than SolidStart. Why not Astro?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;One row in that table deserves a straight answer: Astro + HTMX is 34.3 kB, 7 kB smaller than SolidStart. Both of my sites are content-heavy marketing sites. By byte logic alone, Astro wins.&lt;/p&gt;

&lt;p&gt;Astro's model is content first, zero JS by default, interactivity added through islands. The catch is that when you write the interactive parts, each island hosts a component framework anyway, and the project now speaks two dialects: &lt;code&gt;.astro&lt;/code&gt; templates for page structure, the island framework for behavior, state passed across the seam. And &lt;code&gt;.astro&lt;/code&gt; is one more custom file format, so the upgrade-queue problem from the last section applies here too.&lt;/p&gt;

&lt;p&gt;Neither site is actually static. keyecho.app runs Stripe checkout, a subscribe flow, and SSR in five languages, with sound-pack sales pages on the way. upweb.dev has quietly grown into a small system: double-opt-in subscriptions, posts and newsletter archives managed in Broadside, and on every publish a webhook hits the site, verifies its signature, dedupes replays, clears the server content cache, then purges Cloudflare by cache tag. New articles go live without a deploy. All of that lives in SolidStart API routes, and the interaction density only goes up from here. One component model covering both the static and the dynamic parts is worth 7 kB to me.&lt;/p&gt;

&lt;p&gt;If your site is a pure blog or docs and changes three times a year, Astro is the better answer, not SolidStart. With a bigger team the best practice is to split outright: landing pages on Astro or SolidStart, and the console on its own subdomain with its own stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The ecosystem bill: TanStack covers the worst of it, components you grow yourself&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;SolidStart is not a silver bullet, and its biggest weakness is the ecosystem. Most things React has, Solid has an equivalent for, one maturity tier down and with fewer options. Part of that you tolerate. Part of it has workarounds.&lt;/p&gt;

&lt;p&gt;The workaround with the widest coverage is TanStack. Router, Query, Form, Table, Virtual: every package is a core plus adapters, and Solid gets first-class ones. I run the Solid version of TanStack Start in production at &lt;a href="https://difflore.dev/" rel="noopener noreferrer"&gt;difflore.dev&lt;/a&gt;: solid-router, solid-query, and oRPC, a full backend with auth, a database, and AI calls, and no missing parts so far. That one vendor crosses off the heaviest items on the list.&lt;/p&gt;

&lt;p&gt;The larger trend helps too: infrastructure is going framework-agnostic. Vite, Nitro, Drizzle, Zod, oRPC, better-auth do not care what renders your UI, and headless UI has moved from React-only toward state-machine cores with adapters for everyone. The framework-exclusive share of the ecosystem is shrinking. The flip side deserves saying out loud: every convenience you take from a React-only library raises the wall you would have to climb to ever leave. An ecosystem is an asset and a shackle at the same time.&lt;/p&gt;

&lt;p&gt;The gap that remains is the polished component library. On the React side the standard is shadcn/ui; Solid has community ports, at a fraction of the traction. This does not slow me down, and shadcn itself demonstrates why: it ships no npm package. It copies component source into your repo, turning components from a dependency into your own code. Definitions like that are exactly what AI produces fast. One component, written twice, a React version and a Solid version, is minutes of work. None of my current interfaces use a prebuilt library: both sites are hand-written components on top of tokens, the React admin uses Base UI, the Solid side uses Kobalte, all headless primitives with the look and behavior defined by me. AI solved the output problem. What it did not solve is how to design a component API, where state should live, and how tokens get enforced. That skill transfers between React and Solid completely, and the shallower the component-library moat gets, the more it is worth practicing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Styling: utility classes lost the default slot&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The current state first, so this does not read like a takedown: KeyEcho desktop shipped 1.0 on UnoCSS, still runs it today, and I have no plan to rip it out. That UI is small and fixed, there is no design file to match, and the panels rarely change once settled, so utility classes have little room to go wrong there. Admin platforms and marketing sites are a different shape: pages keep multiplying, styles track redesigns, and there is a design language to defend. The two failure modes below belong to that second shape.&lt;/p&gt;

&lt;p&gt;Utility classes fail in AI hands at two points.&lt;/p&gt;

&lt;p&gt;The first is token drift, and Tailwind and UnoCSS are equally exposed. The project has its own design tokens, and the model still reaches for the default scale in its training memory, or drops in an arbitrary value. &lt;code&gt;gap-3&lt;/code&gt; and &lt;code&gt;gap-[12px]&lt;/code&gt; look nearly identical in review, and today they render exactly the same. The difference is that the second one has left the token system, so the next scale change misses it. Every line is legal, and the design system forks a little more with each PR. I have watched this happen more than once. Tailwind v4's &lt;code&gt;@theme&lt;/code&gt; cleans up token definitions; arbitrary values remain forever legal.&lt;/p&gt;

&lt;p&gt;The second is size. Atomic CSS rests on class reuse: the stylesheet is supposed to stop growing with page count. Enough arbitrary values and that premise collapses. Every &lt;code&gt;w-[347px]&lt;/code&gt; is a single-use rule, the stylesheet grows with the PR count, and so do the class strings in the HTML. A constraint model this permissive compiles everything, and the cost gets billed somewhere else.&lt;/p&gt;

&lt;p&gt;vanilla-extract turns tokens into TypeScript exports. Styles live in &lt;code&gt;.css.ts&lt;/code&gt; files, colors have to be imported from the theme, a misspelled variable is a type error, and a hex value invented from memory does not survive type checking. The theme contract on upweb.dev defines 16 tokens with &lt;code&gt;createThemeContract&lt;/code&gt;; light and dark must each assign every key, and one missing dark value fails the build. The rule no longer depends on anyone's memory, or on whether the model read the docs. The output is plain CSS with zero runtime, split by route: a visitor downloads only the styles the current page uses, never a site-wide sheet.&lt;/p&gt;

&lt;p&gt;The oldest complaint about CSS-in-TS is naming. AI flipped that one: the model does the naming, I only review, and a named block reads faster than a thirty-character utility string.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The rest of the CSS field&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Zero runtime is the floor, which clears the runtime approaches immediately. styled-components and Emotion generate styles in the browser and need extra serialization for SSR, and styled-components is officially in maintenance mode. CSS Modules are zero-runtime, but tokens are string conventions the type system cannot see, so the theme contract is enforced by hoping.&lt;/p&gt;

&lt;p&gt;Panda CSS and StyleX are in vanilla-extract's lane: typed, compile-time.&lt;/p&gt;

&lt;p&gt;Panda loses on operational shape. It codegens an entire &lt;code&gt;styled-system&lt;/code&gt; output directory that must be regenerated whenever tokens change, and the call sites look like a runtime library while behaving like build-time static extraction, so any dynamic object shape (computed keys, spread from a function) gets silently dropped from the stylesheet. Too much pipeline for a content site.&lt;/p&gt;

&lt;p&gt;StyleX has nothing wrong with it as a design, and defineVars enforces tokens well, but it is stuck on ecosystem status: two community Vite plugins died in sequence, the official unplugin integration arrived late, and there is no established path in SolidStart. For infrastructure I only pick what the current build chain treats as a first-class citizen. vanilla-extract's official vite-plugin has been stable for years and drops into any Vite-based framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Where React still runs&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A heavily interactive product I work on at my day job runs React 19 with React Compiler on TanStack Start, and runs well. A team's weight table is different from a solo one: the heavyweight components, editors above all, are written in React, so changing runtimes means a rewrite plus a full regression pass, and QA hours cost more than any framework difference. That alone settled the runtime. At the meta-framework layer they picked TanStack Start over Next.js for equally practical reasons: the product barely touches RSC, so Next.js's architectural complexity buys nothing there, and the Vite toolchain plus fully typed routing came along for free. Loren's table prices that choice at 58 kB: React 19 either way, 118.2 against 176.1, a third of the bytes.&lt;/p&gt;

&lt;p&gt;Broadside's admin is a different story. It also runs React with TanStack Start, for a less flattering reason: I needed the platform running and had no time to switch stacks. The plan is to move it onto TanStack Start's Solid adapter, the same combination as difflore.dev: keep the ecosystem, swap the runtime.&lt;/p&gt;

&lt;p&gt;Broadside is my self-hosted newsletter platform: an MCP server is built in, an agent drafts, models watch the numbers, and I review and press send. Once it is cleaned up I am open-sourcing it. Separate post then.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Five rules from three decisions&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick frameworks by client-side bytes.&lt;/strong&gt; AI erased learning curves from the weight table. Runtime cost lives in the architecture, and no prompt removes it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A constraint only counts if the compiler enforces it.&lt;/strong&gt; A rule that fails silently does not exist at AI throughput. Docs get diluted over a long session; type errors do not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every extra language layer is another place in the upgrade queue.&lt;/strong&gt; TS 7 this month: JSX switched on day one, template DSLs wait until October.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefer framework-agnostic ecosystems, and grow your own component layer.&lt;/strong&gt; A single-framework library's convenience and its lock-in come from the same place. Headless primitives plus your own tokens: AI supplies the volume, you supply the rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Change the default, do not relitigate the past.&lt;/strong&gt; UnoCSS still runs the desktop app, and the day-job React product runs fine. New defaults apply to line one of new repos.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://upweb.dev/" rel="noopener noreferrer"&gt;upweb.dev&lt;/a&gt; and &lt;a href="https://keyecho.app/" rel="noopener noreferrer"&gt;keyecho.app&lt;/a&gt; both run on SolidStart + vanilla-extract today. The next repo I open will probably start there too, until some project's shape changes the answer again.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>How I made a Rust hot path 27x faster, and the AI fix I refused to merge</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Tue, 14 Jul 2026 16:38:47 +0000</pubDate>
      <link>https://dev.to/zacharylee/how-i-made-a-rust-hot-path-27x-faster-and-the-ai-fix-i-refused-to-merge-3llg</link>
      <guid>https://dev.to/zacharylee/how-i-made-a-rust-hot-path-27x-faster-and-the-ai-fix-i-refused-to-merge-3llg</guid>
      <description>&lt;p&gt;Two years ago I open-sourced KeyEcho, a small desktop app that plays a mechanical-keyboard sound the instant you press a key. It got 800+ stars. Then I shipped v0.0.5 in July 2024 and went quiet.&lt;/p&gt;

&lt;p&gt;The issues never stopped. People asked for sound packs, reported platform bugs, and kept using a thing I had stopped maintaining. This month I came back and shipped 1.0 in a single PR: 130 files, 11,405 lines added and 9,292 removed. The core of it was a rebuild of the audio hot path. The cached-lookup microbenchmark went from 1184.07 ns/op with 66.84 KiB copied per key to 43.50 ns/op with zero sample bytes copied. That is 27x on the average slice and 38x on the largest.&lt;/p&gt;

&lt;p&gt;I built it with an AI agent writing a lot of the code. This post is how the rework works, why Rust made that safe to do fast, and the one change the agent suggested that looked clean and would have quietly broken a feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hot path
&lt;/h2&gt;

&lt;p&gt;KeyEcho's latency-sensitive path is short. A global keyboard hook fires on every key event. The first key-down of each press is pushed into a bounded queue. An audio thread pulls from the queue, maps the key to a slice of the selected sound pack, and plays it locally.&lt;/p&gt;

&lt;p&gt;Because the path is short, anything left inside it is paid on every keystroke: any decode work, any allocation, any sample copy, any lock. The whole game is getting those out of the per-key path.&lt;/p&gt;

&lt;h2&gt;
  
  
  v0.0.5 was already fast
&lt;/h2&gt;

&lt;p&gt;Credit where it is due. v0.0.5 was a light, quick thing: Tauri + Rust, small builds, low memory; native keyboard listening I wrote by hand against each platform's API, with almost no unsafe; lossless WAV audio with no decompression step; and it already cached decoded audio in an LRU, so hitting the same key twice did not decode twice. It ran for two years and a few hundred people used it. It was not slow software.&lt;/p&gt;

&lt;p&gt;But "already fast" and "no headroom left" are two different things. Even on a cache hit, each key press still copied the samples (66.84 KiB in the benchmark) and went through a global mutex shared with pack switching and volume changes. A cache miss still decoded on the spot. What 1.0 removed is exactly those: that copy, that lock, and the fact that cache misses happen at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rebuild
&lt;/h2&gt;

&lt;p&gt;The rebuild came down to four moves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Predecode once, when a pack is selected.&lt;/strong&gt; A sound pack is a folder with a &lt;code&gt;sound.ogg&lt;/code&gt; and a &lt;code&gt;config.json&lt;/code&gt;. The config maps each key to a slice of the audio: &lt;code&gt;key -&amp;gt; [start_ms, duration_ms]&lt;/code&gt;. When you select a pack, every slice is decoded up front, one time. Nothing decodes during a keystroke.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deduplicate identical slices.&lt;/strong&gt; Many keys point at the same slice, so decoding per key would decode the same audio many times. The builder keys a map on the &lt;code&gt;(start_ms, duration_ms)&lt;/code&gt; pair, decodes each unique slice once, and shares it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Decode each unique slice once; identical slices share one buffer.&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;slice_sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u64&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="n"&gt;AudioSource&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;key_sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AudioSource&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;defines&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slice_sources&lt;/span&gt;
        &lt;span class="nf"&gt;.entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.or_insert_with&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start_ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration_ms&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration_ms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Vec&amp;lt;f32&amp;gt;, once&lt;/span&gt;
            &lt;span class="nn"&gt;AudioSource&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Arc clone, not a sample copy&lt;/span&gt;
    &lt;span class="n"&gt;key_sources&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Zero-copy playback.&lt;/strong&gt; Decoded samples live in an &lt;code&gt;Arc&amp;lt;[f32]&amp;gt;&lt;/code&gt;. A key lookup returns a clone of that Arc, which is a reference-count bump, not a sample copy. The per-key cost went to zero bytes copied.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drop the global mutex.&lt;/strong&gt; The old path guarded the current sound and the volume with a mutex. The new playback handle holds the current sound in an &lt;code&gt;ArcSwapOption&amp;lt;KeySound&amp;gt;&lt;/code&gt; and the volume in an &lt;code&gt;AtomicU32&lt;/code&gt; (via &lt;code&gt;f32::to_bits&lt;/code&gt;). Looking up a key is a lock-free load:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;PlaybackSoundpack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;current_sound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ArcSwapOption&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KeySound&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;volume_bits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AtomicU32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;source_for_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AudioSource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.current_sound&lt;/span&gt;&lt;span class="nf"&gt;.load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;          &lt;span class="c1"&gt;// lock-free&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sound&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nf"&gt;.key_source&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// map get + Arc clone&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_bits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.volume_bits&lt;/span&gt;&lt;span class="nf"&gt;.load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Relaxed&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;volume&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;Predecoding trades work up front for RAM, so it needs two guardrails. Key events go through a bounded queue, so a burst applies backpressure instead of growing memory without limit. And a pack has to fit a decoded-sample budget of 10 MiB: before it loads, the app estimates decoded size from the unique slice durations and refuses anything larger. Predecoding is only safe when it is bounded.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;Release-build microbenchmarks of the lookup path:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;v0.0.5&lt;/th&gt;
&lt;th&gt;v1.0&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cached lookup, average slice&lt;/td&gt;
&lt;td&gt;1184.07 ns/op; 66.84 KiB copied&lt;/td&gt;
&lt;td&gt;43.50 ns/op; 0 bytes copied&lt;/td&gt;
&lt;td&gt;27.2x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cached lookup, largest slice&lt;/td&gt;
&lt;td&gt;1638.57 ns/op; 98.88 KiB copied&lt;/td&gt;
&lt;td&gt;43.10 ns/op; 0 bytes copied&lt;/td&gt;
&lt;td&gt;38.0x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Press/release gate&lt;/td&gt;
&lt;td&gt;58.82 ns/tap; 2 messages&lt;/td&gt;
&lt;td&gt;54.69 ns/tap; 1 message&lt;/td&gt;
&lt;td&gt;half the messages&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are microbenchmarks of the lookup path, not end-to-end speaker latency, which depends on your OS and hardware. The method and memory budgets are in &lt;code&gt;docs/performance.md&lt;/code&gt;, and the benchmarks ship in the repo. Run &lt;code&gt;pnpm run bench:audio&lt;/code&gt; if you do not believe me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Rust made this safe to do fast
&lt;/h2&gt;

&lt;p&gt;I leaned on the agent for most of this diff. The reason that felt safe is the compiler.&lt;/p&gt;

&lt;p&gt;The borrow checker and the type system are the first reviewer for AI-generated code. Most wrong code does not survive &lt;code&gt;cargo check&lt;/code&gt;. Moving shared audio buffers to &lt;code&gt;Arc&amp;lt;[f32]&amp;gt;&lt;/code&gt; and removing the mutex are exactly the changes where a mistake is an aliasing or a &lt;code&gt;Send&lt;/code&gt;/&lt;code&gt;Sync&lt;/code&gt; error, and Rust rejects those at compile time, before they reach a human review or a user. The more of the diff an agent writes, the more that guardrail is worth.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the agent actually did
&lt;/h2&gt;

&lt;p&gt;Not "it wrote the app." The useful work was narrower and, honestly, more valuable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Migration assistant.&lt;/strong&gt; Tauri 1 to 2 touches config, permissions, the updater, and every plugin boundary. A partner that has read all the migration docs saves real hours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot-path auditor.&lt;/strong&gt; It went through the old playback path with me line by line and drove the predecode, shared-buffer, no-mutex rework above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backlog triage.&lt;/strong&gt; I had it read every open issue and sort by what belonged in 1.0. One of them was a 10-month-old request from someone who had offered to pay for a specific sound. Replying to it after 1.0 turned into the project's first paying customer. The backlog was demand I had stopped reading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmark and docs discipline.&lt;/strong&gt; It kept the performance notes conclusion-first, reproducible, and honest about what the numbers do and do not measure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I rarely gave step-by-step orders. I gave goals ("get sample copies in the key path to zero", "sort the backlog by what belongs in 1.0") and reviewed at the checkpoints. The speedups themselves come from the rework: predecoding, shared buffers, the dropped mutex, the bounded queue. The agent is what made finding, doing, and verifying that whole loop fast enough to actually happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The change that looked clean and wasn't
&lt;/h2&gt;

&lt;p&gt;This is the one I want you to steal.&lt;/p&gt;

&lt;p&gt;CI for the Linux armv7 build failed under QEMU: libgit2 could not fetch a git dependency. The agent's fix was clean. Drop the git pin on the audio crate and use the crates.io release instead. CI went green.&lt;/p&gt;

&lt;p&gt;I rejected it. That pin exists for a reason that is written nowhere in the code. It holds &lt;code&gt;cpal&lt;/code&gt; at 0.18, which ships the default-device rerouting (and its &lt;code&gt;DeviceChanged&lt;/code&gt; notification) that makes the sound follow you when you unplug headphones or switch to a Bluetooth speaker. Reverting to the crates.io version silently downgrades &lt;code&gt;cpal&lt;/code&gt; to 0.17.3 and drops device-following. Two user issues, #41 and #20, were about exactly that behavior. No test covered "unplug the device and the sound follows," so nothing would have caught the regression except knowing why the pin was there.&lt;/p&gt;

&lt;p&gt;The real fix was to vendor the dependencies with &lt;code&gt;cargo vendor&lt;/code&gt; and build offline inside QEMU. The pin never moved.&lt;/p&gt;

&lt;p&gt;Two lessons I now treat as rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the "why" next to every pin, hack, and magic number, in a comment or the project's AI rules file. Your agent has no memory of the incident that put it there. It is a talented engineer with zero context on your project.&lt;/li&gt;
&lt;li&gt;Never accept a dependency version change you did not ask for, even when CI is green. A green pipeline proves the tests pass. It does not prove the tests cover what you are about to lose.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What I cut
&lt;/h2&gt;

&lt;p&gt;The armv7 build ran about two hours under emulation, and there was no clear user for 32-bit ARM Linux. I dropped it from 1.0.&lt;/p&gt;

&lt;p&gt;An agent has no sense of sunk cost or opportunity cost. It will keep optimizing a build target forever if you let it. It can get arbitrarily close to "done." Deciding to stop is a human job.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the work was structured
&lt;/h2&gt;

&lt;p&gt;Two smaller notes from shipping this.&lt;/p&gt;

&lt;p&gt;Before release I ran an AI review pass inside git worktrees, so several agents could scan the code and propose fixes in parallel without touching the main tree. Each agent's output was a proposal, merged only after review. Exploration parallelizes cleanly. The synthesis still has to happen in one head, because each agent only sees its own slice.&lt;/p&gt;

&lt;p&gt;The models are also starting to specialize. Claude Fable feels like an engineer who thinks outside the box and keeps surfacing angles I had missed. GPT-5.6 is the best executor I have used: hand it a decided plan and the code comes back close to perfect. It felt like running a two-person team where one thinks, one builds, and I decide and sign off.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 1.0 is
&lt;/h2&gt;

&lt;p&gt;Still free, still open source. AGPL-3.0, small native installers, no account, no analytics. Rebuilt on Tauri 2 + SolidJS. Signed Windows builds and notarized macOS builds, which cut down unsigned-app warnings and antivirus false positives. Linux packages for x64 and ARM64.&lt;/p&gt;

&lt;p&gt;You can try it without downloading anything: open &lt;a href="https://keyecho.app" rel="noopener noreferrer"&gt;keyecho.app&lt;/a&gt; and type, and you will hear it in the browser. The benchmarks and method are in the repo.&lt;/p&gt;

&lt;p&gt;I write a weekly build log about shipping real production systems with AI agents, honest numbers only. Subscribe at &lt;a href="https://upweb.dev" rel="noopener noreferrer"&gt;upweb.dev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Differences Between "export default xx" and "export {xx as default}"</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Tue, 21 Oct 2025 03:57:14 +0000</pubDate>
      <link>https://dev.to/zacharylee/the-differences-between-export-default-xx-and-export-xx-as-default-4ab3</link>
      <guid>https://dev.to/zacharylee/the-differences-between-export-default-xx-and-export-xx-as-default-4ab3</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published in&lt;/em&gt; &lt;a href="https://upweb.dev/posts/differences-between-export-default" rel="noopener noreferrer"&gt;my newsletter&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basics of JavaScript Modules
&lt;/h2&gt;

&lt;p&gt;Modules are self-contained pieces of code that can be imported and used in other modules. They help developers keep code organized, maintainable, and easy to understand.&lt;/p&gt;

&lt;p&gt;To work with modules, you need to understand the import and export syntax. Here’s a quick recap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;import&lt;/code&gt;: Used to import named exports or default exports from other modules.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;export&lt;/code&gt;: Used to export values, functions, or classes from a module, making them available for other modules to import.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are two types of exports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Named exports: You can have multiple named exports in a module. They are explicitly imported using their names.&lt;/li&gt;
&lt;li&gt;Default exports: Each module can have only one default export. They are imported without specifying a name.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Behavior of export { xxx as default }
&lt;/h2&gt;

&lt;p&gt;In JavaScript, imports are live bindings, or references, rather than values. This means that when you import a variable from another module, you’re importing a reference to that variable, not a copy of its value.&lt;/p&gt;

&lt;p&gt;Consider the following example:&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="c1"&gt;// math.js&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;888&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="c1"&gt;// app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;value&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;./math.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ?&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, guess what &lt;code&gt;value&lt;/code&gt; is printed?&lt;/p&gt;

&lt;p&gt;The answer is &lt;code&gt;888&lt;/code&gt; not &lt;code&gt;1&lt;/code&gt;. This is because &lt;code&gt;export&lt;/code&gt; exports references.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Behavior of export default xxx
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;export default&lt;/code&gt; syntax is used to export a default value from a module. However, when you use &lt;code&gt;export default value&lt;/code&gt;, the current value is exported, not a live reference.&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="c1"&gt;// math.js&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;888&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;value&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;./math.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, when the &lt;code&gt;value&lt;/code&gt; variable in &lt;code&gt;math.js&lt;/code&gt; changes, the &lt;code&gt;value&lt;/code&gt; variable in &lt;code&gt;app.js&lt;/code&gt; does not change. This is because &lt;code&gt;value&lt;/code&gt; holds the current value at import time, not a live reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Export Reference Data Types
&lt;/h2&gt;

&lt;p&gt;As you can see, we exported primitive data types earlier, but what if we exported reference data types?&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="c1"&gt;// math.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;current&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="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;888&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// OR&lt;/span&gt;
&lt;span class="c1"&gt;// export { value as default };&lt;/span&gt;
&lt;span class="c1"&gt;// app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;value&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;./math.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, there is no difference between &lt;code&gt;export default xxx&lt;/code&gt; and &lt;code&gt;export { xxx as default }&lt;/code&gt; when dealing with reference data types. It can be understood that they are always reference types in JavaScript, and they will not be &lt;a href="https://webdeveloper.beehiiv.com/p/get-perfect-deep-copy-javascript" rel="noopener noreferrer"&gt;deeply copied&lt;/a&gt; when exported.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices and Recommendations
&lt;/h2&gt;

&lt;p&gt;While both &lt;code&gt;export default xxx&lt;/code&gt; and &lt;code&gt;export { xxx as default }&lt;/code&gt; can be used to export default values, but their behavior differs in certain scenarios. Here are some recommendations to help you choose the right syntax:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;export default xxx&lt;/code&gt; when you want to export a value, such as a string, or number, and you don't need live bindings.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;export { xxx as default }&lt;/code&gt; when you need live binding, especially when the exported value may change over time (not recommended).&lt;/li&gt;
&lt;li&gt;For reference data types, either syntax can be used, since they always export a reference.&lt;/li&gt;
&lt;li&gt;A related suggestion: For code readability and maintainability, it is recommended to use named exports instead of default exports, &lt;a href="https://webdeveloper.beehiiv.com/p/avoid-default-exports-javascript-modules" rel="noopener noreferrer"&gt;here is why&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The differences between &lt;code&gt;export default xxx&lt;/code&gt; and &lt;code&gt;export { xxx as default }&lt;/code&gt; in JavaScript may appear subtle, but they can have an impact on your code's behavior. Hope this article is helpful to you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you find this helpful, &lt;a href="https://upweb.dev/" rel="noopener noreferrer"&gt;please consider subscribing&lt;/a&gt; to my newsletter for more insights on web development. Thank you for reading!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How does HTTPS work</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Tue, 21 Oct 2025 03:39:22 +0000</pubDate>
      <link>https://dev.to/zacharylee/how-does-https-work-2i68</link>
      <guid>https://dev.to/zacharylee/how-does-https-work-2i68</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published in&lt;/em&gt; &lt;a href="https://upweb.dev/posts/how-does-https-work" rel="noopener noreferrer"&gt;&lt;em&gt;my newsletter&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hypertext Transfer Protocol (HTTP) is an application-layer protocol for transmitting hypermedia documents, such as HTML. It was originally designed for communication between web browsers and web servers, but with later development, its application is not limited here, the mature software and hardware environment makes it the infrastructure of the Internet. I believe you must have been exposed to it, it is just like water or air in software development, it’s all too common.&lt;/p&gt;

&lt;p&gt;But as programmers, we may ignore a lot of key information because of its commonness, resulting in some problems in daily work development and do not know how to solve them. Then this article will introduce you to one of the key pieces of information — HTTPS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why HTTPS?
&lt;/h3&gt;

&lt;p&gt;Why does it appear? What problem does it appear to solve?&lt;/p&gt;

&lt;p&gt;To answer the above questions, we need to first analyze the characteristics of HTTP.&lt;/p&gt;

&lt;p&gt;The characteristics of HTTP are simple, flexible, and easy to extend, but at the same time it is stateless (you can use Cookie technology to achieve “stateful”), and it is transmitted in clear text, which means that its data is completely visible and easy to be eavesdropped or forgery.&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%2F5bpfgpujje703m7bakul.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%2F5bpfgpujje703m7bakul.png" alt="img" width="665" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the same time, HTTP is widely used, so scenarios with high-security requirements such as online payment require corresponding security measures, so HTTPS appeared.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is HTTPS?
&lt;/h3&gt;

&lt;p&gt;The RFC document of HTTPS has very little content. It specifies a new protocol name “HTTPS” and the default port number is 443, which is to insert a “security layer” between TCP and HTTP.&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%2F8beonk4vzt398bpmwmpm.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%2F8beonk4vzt398bpmwmpm.png" alt="img" width="411" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This security layer, as the name implies, encrypts the data sent and decrypts the data received so that the middleman cannot steal the information. Then as long as you understand this security layer, you also understand HTTPS.&lt;/p&gt;

&lt;p&gt;SSL is the Secure Sockets Layer, which is at layer 6 (Presentation) in the &lt;a href="https://en.wikipedia.org/wiki/OSI_model?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=how-does-https-work" rel="noopener noreferrer"&gt;OSI model&lt;/a&gt;. It was invented by Netscape in 1994. There are two versions, v2 and v3, and v1 was never disclosed because of its flaws.&lt;/p&gt;

&lt;p&gt;When SSL developed to v3, it proved itself to be a very good secure communication protocol, so the Internet Engineering Group IETF renamed it TLS (Transport Layer Security) in 1999, and officially standardized, the version number from 1.0 is recalculated, so TLS1.0 is actually SSL 3.1.&lt;/p&gt;

&lt;p&gt;At present, TLS has developed three versions, namely 1.1 in 2006, 1.2 in 2008, and 1.3 in 2018, and each new version is continuously enhancing security and performance. The most widely used TLS 1.2 at present, so let’s unravel the secrets of TLS 1.2!&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTPS (TLS 1.2) secret
&lt;/h3&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%2Fa06g07l5m31v9oqk8kkd.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%2Fa06g07l5m31v9oqk8kkd.png" alt="img" width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me explain the above image first:&lt;/p&gt;

&lt;p&gt;Handshake phase:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client generates a client-random and then passes the symmetric cipher suites and asymmetric cipher suites it supports to the server.&lt;/li&gt;
&lt;li&gt;After the server receives it, it will select the encryption algorithm to use from the encryption suite, generate a server-random and pass the certificate of the service to the client.&lt;/li&gt;
&lt;li&gt;After the client receives it, it will first verify the certificate. If the certificate is valid, it will generate a pre-master random number, encrypt it with the public key in the certificate and the selected &lt;strong&gt;asymmetric encryption algorithm&lt;/strong&gt; , and then pass it to the server. It will also come with a Client finished confirmation message.&lt;/li&gt;
&lt;li&gt;The server receives the encrypted pre-master and can decrypt it using the private key. A confirmation message of the Server finished will then be passed to the Client.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Transfer stage:&lt;/p&gt;

&lt;p&gt;After the handshake phase, both ends already have client-random, server-random, and pre-master. Mix them to generate the final master secret, and use the previously selected &lt;strong&gt;symmetric encryption algorithm&lt;/strong&gt; to encrypt and decrypt the required transmitted data.&lt;/p&gt;

&lt;p&gt;God, is it so troublesome that I just want to send data? I thought the same thing when I first saw it.&lt;/p&gt;

&lt;p&gt;Let’s be patient and take a closer look, it’s actually not that difficult.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are symmetric encryption and asymmetric encryption?
&lt;/h3&gt;

&lt;p&gt;Let’s first explain the symmetric encryption and asymmetric encryption mentioned above.&lt;/p&gt;

&lt;p&gt;Symmetric encryption means that the same key is used for encryption and decryption. Asymmetric encryption has two keys, A and B. If you use the A key to encrypt, you can only use the B key to decrypt; conversely, If you want the B key to encrypt, you can only use the A key to decrypt.&lt;/p&gt;

&lt;p&gt;In the handshake phase of HTTPS, we use asymmetric encryption, why? Suppose we use symmetric encryption:&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%2Fwvn82bieqss9vjqq0349.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%2Fwvn82bieqss9vjqq0349.png" alt="img" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As can be seen from the above figure, the client-random and service-random and symmetric encryption suites passed in are in clear text, which leads to the fact that if a hacker gets the data, they can generate the same key, which can be cracked data.&lt;/p&gt;

&lt;p&gt;If we use asymmetric encryption, the pre-master encrypted by the client can only decrypt the key stored by the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a CA certificate?
&lt;/h3&gt;

&lt;p&gt;Because once the hacker uses DNS hijacking and replaces the IP address that the user wants to access with the hacker’s IP address, the request will be sent directly to the hacker’s service. He implements the public key and private key on his service, and the client completely does not know!&lt;/p&gt;

&lt;p&gt;So we need the CA (Certificate Authority) certificate authority to help us prove that this service is the service we want to access!&lt;/p&gt;

&lt;h3&gt;
  
  
  How to check the validity of the CA certificate?
&lt;/h3&gt;

&lt;p&gt;The client will verify according to the following process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check if the certificate has expired&lt;/li&gt;
&lt;li&gt;Check if revoked by CA&lt;/li&gt;
&lt;li&gt;Check whether the certificate is issued by the CA authority. We will use the original certificate information to calculate the message digest, use the CA public key to decrypt the digital signature in the certificate, and then compare the message digest with the digital signature.&lt;/li&gt;
&lt;li&gt;Prove the legitimacy of the CA organization. The CA certification chain is a tree structure, and the root CA certificate is found step by step. The root CA certificate (self-signed certificate) is built into the system. The requirements are very strict. If the root CA certificate is valid, it also proves that the certificate is valid. But if malware injects an illegitimate root CA certificate into a user’s system, there’s no way around it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why is the transmission phase symmetric encryption?
&lt;/h3&gt;

&lt;p&gt;This is because the symmetric encryption algorithm usually uses bit operations, and the asymmetric encryption is mainly the calculation of some large number multiplications in RSA, so the efficiency of asymmetric encryption is very low, which will seriously affect the transmission speed and make the user experience very poor. And the master secret we generated in the handshake phase is secure enough, so we can use symmetric encryption in the transfer phase.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you find this helpful, &lt;a href="https://upweb.dev/" rel="noopener noreferrer"&gt;please consider subscribing&lt;/a&gt; to my newsletter for more insights on web development. Thank you for reading!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Ditch Git Checkout: Use Git Switch and Git Restore Instead</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Mon, 14 Oct 2024 02:45:48 +0000</pubDate>
      <link>https://dev.to/zacharylee/ditch-git-checkout-use-git-switch-and-git-restore-instead-51e6</link>
      <guid>https://dev.to/zacharylee/ditch-git-checkout-use-git-switch-and-git-restore-instead-51e6</guid>
      <description>&lt;p&gt;If you use Git in your daily work, &lt;code&gt;git checkout&lt;/code&gt; is a common command. It's often used to switch branches, and if you look at the &lt;a href="https://git-scm.com/docs/git-checkout?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=ditch-git-checkout-use-git-switch-and-git-restore-instead" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, you can see the phrase &lt;em&gt;"switch branches or restore working tree files"&lt;/em&gt;. But UNIX should be &lt;em&gt;&lt;a href="https://en.wikipedia.org/wiki/Unix_philosophy?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=ditch-git-checkout-use-git-switch-and-git-restore-instead#Do_One_Thing_and_Do_It_Well" rel="noopener noreferrer"&gt;Do One Thing and Do It Well&lt;/a&gt;&lt;/em&gt;. This was confusing, so Git 2.23 brought a pair of commands to replace it.&lt;/p&gt;




&lt;p&gt;Before introducing how it works, we need to briefly understand its associated Git concepts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Working copy (working tree file): It refers to the file in the repository that appears on the hard disk.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Index (staging area or cache): it refers to you have &lt;code&gt;git add&lt;/code&gt;-ed, or, what would be committed if you were to run &lt;code&gt;git commit&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HEAD: It refers to the “current” or “active” branch, when we need to check out a branch (referring to your attempt to match the branch with what is in the working copy), only one can be checked out at a time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;git checkout&lt;/code&gt; can checkout a branch or create a new branch and checkout into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Switched to branch 'test'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# Switched to a new branch 'test'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# Switch back to the previous branch&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout -

&lt;span class="c"&gt;# Switched to a commit&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout master~1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;code&gt;git switch&lt;/code&gt; is used to take over branch related, so it can also do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Switched to branch 'test'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git switch &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# Switched to a new branch 'test'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git switch &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# Switch back to the previous branch&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git switch -

&lt;span class="c"&gt;# Switched to a commit&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git switch &lt;span class="nt"&gt;-d&lt;/span&gt; master~1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And as we said at the beginning, &lt;code&gt;git checkout&lt;/code&gt; can also restore working tree files. This part of the feature is taken over by &lt;code&gt;git restore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the past, we could use &lt;code&gt;git checkout -- main.c&lt;/code&gt; to restore the working tree file from the index, the syntax was &lt;code&gt;git checkout [treeish] -- &amp;lt;filename&amp;gt;&lt;/code&gt;, where &lt;code&gt;treeish&lt;/code&gt; could be specified as the source. Simple examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Restoring the working tree from the index&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout &lt;span class="nt"&gt;--&lt;/span&gt; ./main.c

&lt;span class="c"&gt;# Restoring index content from HEAD&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git reset &lt;span class="nt"&gt;--&lt;/span&gt; ./main.c

&lt;span class="c"&gt;# Restoring the working tree and index from HEAD&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout HEAD &lt;span class="nt"&gt;--&lt;/span&gt; ./main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that when restoring index content from HEAD, we can only use &lt;code&gt;git reset&lt;/code&gt;, and &lt;code&gt;git checkout&lt;/code&gt; has no corresponding option.&lt;/p&gt;

&lt;p&gt;Show with a graph:&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%2Ffpi3apahzkb7w0mlgvj2.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%2Ffpi3apahzkb7w0mlgvj2.png" width="712" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git restore&lt;/code&gt; makes it easier to determine which files will be restored, and where they will be restored. The following options specify the restore location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-W
--worktree
-S
--staged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, &lt;code&gt;-W&lt;/code&gt; and &lt;code&gt;--worktree&lt;/code&gt; will restore the working tree from the index, the same as if no options were specified (like &lt;code&gt;git restore -- ./main.c&lt;/code&gt; ). Whereas &lt;code&gt;-S&lt;/code&gt; and &lt;code&gt;--staged&lt;/code&gt; will restore the index contents from HEAD. When passing both, the index and working tree will be restored from HEAD.&lt;/p&gt;

&lt;p&gt;For instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Restoring the working tree from the index&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git restore &lt;span class="nt"&gt;--&lt;/span&gt; ./main.c
&lt;span class="c"&gt;# Equivalent to&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git restore &lt;span class="nt"&gt;--worktree&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; ./main.c

&lt;span class="c"&gt;# Restoring index content from HEAD&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git restore &lt;span class="nt"&gt;--staged&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; ./main.c

&lt;span class="c"&gt;# Restoring the working tree and index from HEAD&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git restore &lt;span class="nt"&gt;--staged&lt;/span&gt; &lt;span class="nt"&gt;--worktree&lt;/span&gt; ./main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Show with a graph:&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%2F78o5zsphiw7ogxf7z65o.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%2F78o5zsphiw7ogxf7z65o.png" width="780" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above-mentioned is the default, if we want to restore from a different commit, we can use the &lt;code&gt;--source&lt;/code&gt; option. E.g:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Restore `./main.c` in the working tree with the last commit&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git restore &lt;span class="nt"&gt;-s&lt;/span&gt; HEAD^ &lt;span class="nt"&gt;--&lt;/span&gt; ./main.c
&lt;span class="c"&gt;# Equivalent to&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git restore &lt;span class="nt"&gt;--source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;HEAD^ &lt;span class="nt"&gt;--&lt;/span&gt; ./main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another useful &lt;code&gt;git restore&lt;/code&gt; case might be restoring a mishandled file. E.g:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Incorrectly deleted files&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ./main.c

&lt;span class="c"&gt;# Quickly restore main.c from index&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git restore ./main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For batch recovery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Restore all C source files to match the version in the index&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git restore &lt;span class="s1"&gt;'*.c'&lt;/span&gt;

&lt;span class="c"&gt;# Restore all files in the current directory&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git restore &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Restore all working tree files with top pathspec magic&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git restore :/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The features of &lt;code&gt;git checkout&lt;/code&gt; are clearly separated: &lt;code&gt;git switch&lt;/code&gt; is used to switch branches, while &lt;code&gt;git restore&lt;/code&gt; is used to restore working tree files. They provide more explicit semantics, in line with the UNIX philosophy.&lt;/p&gt;

&lt;p&gt;Both commands were proposed in 2019, and as of now, they are experimental. There may be changes, but usually not by much, so you can use them now, they are easier to understand and less confusing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you found this helpful, please consider&lt;/em&gt; &lt;em&gt;&lt;a href="https://webdeveloper.beehiiv.com/subscribe?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=under-the-hood-of-react-router-in-40-lines-of-code&amp;amp;_bhlid=2f26f41cf9803691495f3ae68d43e3d616c1c102" rel="noopener noreferrer"&gt;subscribing to my newsletter&lt;/a&gt;&lt;/em&gt; &lt;em&gt;for more useful articles and tools about web development. Thanks for reading!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Secrets of JavaScript Object Property Order</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Mon, 14 Oct 2024 02:44:09 +0000</pubDate>
      <link>https://dev.to/zacharylee/the-secrets-of-javascript-object-property-order-4oh4</link>
      <guid>https://dev.to/zacharylee/the-secrets-of-javascript-object-property-order-4oh4</guid>
      <description>&lt;p&gt;Someone asked me recently, are JavaScript object properties necessarily unordered and unpredictable?&lt;/p&gt;

&lt;p&gt;Developers with early exposure to JavaScript might answer that &lt;code&gt;Object.keys()&lt;/code&gt; or &lt;code&gt;for...in&lt;/code&gt; returns an unpredictable order of object properties. But is that still the case?&lt;/p&gt;

&lt;p&gt;As you might expect, there are now rules to follow.&lt;/p&gt;

&lt;p&gt;Starting with ECMAScript 2020, &lt;code&gt;Object.keys&lt;/code&gt;, &lt;code&gt;for...in&lt;/code&gt;, &lt;code&gt;Object.getOwnPropertyNames&lt;/code&gt;, and &lt;code&gt;Reflect.ownKeys&lt;/code&gt; all follow the same order of specification. They are:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Own properties are array indexes, in ascending numeric index order
&lt;/h3&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%2Flzavmc45316mmk966ui3.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%2Flzavmc45316mmk966ui3.png" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An array index is a String-valued property key that is a canonical numeric String. And a &lt;a href="http://www.ecma-international.org/ecma-262/10.0/?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=the-secrets-of-javascript-object-property-order#sec-canonicalnumericindexstring" rel="noopener noreferrer"&gt;canonical numeric String&lt;/a&gt; is a String representation of a number that would be produced by &lt;code&gt;ToString&lt;/code&gt;, or the string "-0". So for instance, "012" is &lt;em&gt;not&lt;/em&gt; a canonical numeric String, but "12" is.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Other own String properties, in ascending chronological order of property creation
&lt;/h3&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%2Fis23frjnsc87zefdc90a.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%2Fis23frjnsc87zefdc90a.png" width="800" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above code adds the knowledge point of the event loop. Because &lt;code&gt;setTimeout&lt;/code&gt; is an asynchronous macro task, the &lt;code&gt;c&lt;/code&gt; property has not been added to &lt;code&gt;obj&lt;/code&gt; when &lt;code&gt;console.log&lt;/code&gt; is output.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Own Symbol properties, in ascending chronological order of property creation
&lt;/h3&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%2Fdpeo1wai5ebcf7a4il6d.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%2Fdpeo1wai5ebcf7a4il6d.png" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Symbol property is the same as the String property, in ascending chronological order of property creation. But the &lt;code&gt;Object.keys&lt;/code&gt;, &lt;code&gt;for...in&lt;/code&gt;, &lt;code&gt;Object.getOwnPropertyNames&lt;/code&gt; methods cannot get the object's Symbol properties, &lt;code&gt;Reflect.ownKeys&lt;/code&gt; and &lt;code&gt;Object.getOwnPropertySymbols&lt;/code&gt; can.&lt;/p&gt;

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

&lt;p&gt;When an object’s property keys are a combination of the above types, the object’s non-negative integer keys (enumerable and non-enumerable) are first added to the array in ascending order, then String keys are added in insertion order. Finally, Symbol keys are added in insertion order.&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%2Ff5xbh0qcswd6y4rih3wi.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%2Ff5xbh0qcswd6y4rih3wi.png" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But if you strongly depend on the insertion order, then &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=the-secrets-of-javascript-object-property-order" rel="noopener noreferrer"&gt;Map&lt;/a&gt; guarantees that for you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you found this helpful, please consider&lt;/em&gt; &lt;a href="https://webdeveloper.beehiiv.com/subscribe?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=under-the-hood-of-react-router-in-40-lines-of-code&amp;amp;_bhlid=2f26f41cf9803691495f3ae68d43e3d616c1c102" rel="noopener noreferrer"&gt;&lt;em&gt;subscribing to my newsletter&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for more useful articles and tools about web development. Thanks for reading!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>programming</category>
    </item>
    <item>
      <title>Understanding the infer Keyword in TypeScript</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Fri, 27 Sep 2024 14:58:34 +0000</pubDate>
      <link>https://dev.to/zacharylee/understanding-the-infer-keyword-in-typescript-20mg</link>
      <guid>https://dev.to/zacharylee/understanding-the-infer-keyword-in-typescript-20mg</guid>
      <description>&lt;p&gt;TypeScript, a statically-typed superset of JavaScript, has gained massive popularity in the tech community due to its ability to catch errors early and improve code readability. One of TypeScript’s powerful features is the &lt;code&gt;infer&lt;/code&gt; keyword, which allows developers to write more expressive and dynamic types.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Infer Keyword
&lt;/h1&gt;

&lt;p&gt;Introduced in TypeScript 2.8, the &lt;code&gt;infer&lt;/code&gt; keyword is used within conditional types to create temporary type variables. These type variables can then be used to infer types within a true or false branch of a conditional type. The &lt;code&gt;infer&lt;/code&gt; keyword enables developers to write more dynamic and expressive types, as it allows TypeScript to determine a specific type based on the context in which it's used.&lt;/p&gt;

&lt;p&gt;To better understand how &lt;code&gt;infer&lt;/code&gt; works, let's take a look at the basic syntax of a conditional 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;MyConditionalType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;SomeType&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;TrueType&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FalseType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;T&lt;/code&gt; is a generic type parameter, and &lt;code&gt;SomeType&lt;/code&gt; represents a type that &lt;code&gt;T&lt;/code&gt; is being compared to. If &lt;code&gt;T&lt;/code&gt; extends &lt;code&gt;SomeType&lt;/code&gt;, the type of &lt;code&gt;MyConditionalType&amp;lt;T&amp;gt;&lt;/code&gt; will be &lt;code&gt;TrueType&lt;/code&gt;. If not, it will be &lt;code&gt;FalseType&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, let’s introduce the &lt;code&gt;infer&lt;/code&gt; keyword into the mix:&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;MyInferredType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;SomeType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FalseType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we use the &lt;code&gt;infer&lt;/code&gt; keyword to create a temporary type variable &lt;code&gt;U&lt;/code&gt; within the true branch of the conditional type. If &lt;code&gt;T&lt;/code&gt; extends &lt;code&gt;SomeType&lt;/code&gt;, TypeScript will try to infer the type of &lt;code&gt;U&lt;/code&gt; based on the type of &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;ReturnType&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ReturnType&lt;/code&gt; is a utility type that extracts the return type of a function. It's a perfect example of how the &lt;code&gt;infer&lt;/code&gt; keyword can be used to create dynamic types. Here's the definition of &lt;code&gt;ReturnType&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&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="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this definition, &lt;code&gt;T&lt;/code&gt; is a function type that takes any number of arguments and returns any type. Using the &lt;code&gt;infer&lt;/code&gt; keyword, we create a temporary type variable &lt;code&gt;R&lt;/code&gt; to represent the return type of the function. If &lt;code&gt;T&lt;/code&gt; is a function, TypeScript infers the return type and assigns it to &lt;code&gt;R&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s see &lt;code&gt;ReturnType&lt;/code&gt; in action:&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;function&lt;/span&gt; &lt;span class="nf"&gt;greet&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&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;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;​&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GreetReturnType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// GreetReturnType is inferred as 'string'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;ReturnType&lt;/code&gt; is used to infer the return type of the &lt;code&gt;greet&lt;/code&gt; function, which is &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Parameters&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Another useful utility type that leverages the &lt;code&gt;infer&lt;/code&gt; keyword is &lt;code&gt;Parameters&lt;/code&gt;. This type extracts the parameter types of a function as a tuple. The definition of &lt;code&gt;Parameters&lt;/code&gt; is as follows:&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="nb"&gt;Parameters&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="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&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="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we create a temporary type variable &lt;code&gt;P&lt;/code&gt; to represent the parameter types of the function. If &lt;code&gt;T&lt;/code&gt; is a function, TypeScript infers the parameter types and assigns them to &lt;code&gt;P&lt;/code&gt; as a tuple.&lt;/p&gt;

&lt;p&gt;Let’s look at an example using &lt;code&gt;Parameters&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="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="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="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="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;​&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AddParameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Parameters&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// AddParameters is inferred as [number, number]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;Parameters&lt;/code&gt; is used to infer the parameter types of the &lt;code&gt;add&lt;/code&gt; function, which is a tuple &lt;code&gt;[number, number]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;PromiseType&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;PromiseType&lt;/code&gt; utility type can be used to extract the type that a &lt;code&gt;Promise&lt;/code&gt; resolves to. This is particularly useful when dealing with asynchronous functions. Here's the definition of &lt;code&gt;PromiseType&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PromiseType&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we create a temporary type variable &lt;code&gt;U&lt;/code&gt; to represent the type that the &lt;code&gt;Promise&lt;/code&gt; resolves to. If &lt;code&gt;T&lt;/code&gt; is a &lt;code&gt;Promise&lt;/code&gt;, TypeScript infers the resolved type and assigns it to &lt;code&gt;U&lt;/code&gt;. Here’s 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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fetched data&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="err"&gt;​&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FetchedDataType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PromiseType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// FetchedDataType is inferred as 'string'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;PromiseType&lt;/code&gt; is used to infer the type that the &lt;code&gt;fetchData&lt;/code&gt; function's promise resolves to, which is &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;UnboxArray&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;UnboxArray&lt;/code&gt; utility type can be used to extract the type of the elements within an array. Here's the definition of &lt;code&gt;UnboxArray&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UnboxArray&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="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we create a temporary type variable &lt;code&gt;U&lt;/code&gt; to represent the type of the elements within the array. If &lt;code&gt;T&lt;/code&gt; is an array, TypeScript infers the element type and assigns it to &lt;code&gt;U&lt;/code&gt;. For instance:&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;MyArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ElementType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UnboxArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyArray&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ElementType is inferred as 'number'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;UnboxArray&lt;/code&gt; is used to infer the type of elements within the &lt;code&gt;MyArray&lt;/code&gt; type, which is &lt;code&gt;number&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Limitations
&lt;/h1&gt;

&lt;p&gt;While the &lt;code&gt;infer&lt;/code&gt; keyword is incredibly powerful, it has some limitations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It can only be used within conditional types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It’s not always possible for TypeScript to infer the correct type, especially when dealing with complex or recursive types. In such cases, developers may need to provide additional type annotations or refactor their types to help TypeScript infer the correct type.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;By understanding and leveraging the power of &lt;code&gt;infer&lt;/code&gt;, you can create more flexible TypeScript projects. Start considering incorporating the infer keyword into your toolkit today.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you found this helpful, please consider&lt;/em&gt; &lt;em&gt;&lt;a href="https://webdeveloper.beehiiv.com/subscribe?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=under-the-hood-of-react-router-in-40-lines-of-code&amp;amp;_bhlid=2f26f41cf9803691495f3ae68d43e3d616c1c102" rel="noopener noreferrer"&gt;subscribing to my newsletter&lt;/a&gt;&lt;/em&gt; &lt;em&gt;for more useful articles and tools about web development. Thanks for reading!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How Server-Sent Events (SSE) Work</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Fri, 27 Sep 2024 14:47:11 +0000</pubDate>
      <link>https://dev.to/zacharylee/how-server-sent-events-sse-work-450a</link>
      <guid>https://dev.to/zacharylee/how-server-sent-events-sse-work-450a</guid>
      <description>&lt;p&gt;SSE (Server Sent Events) is not widely used in the world of web development, this article will take a deep dive into what SSE is, how it works, and how it can benefit your application.&lt;/p&gt;




&lt;h1&gt;
  
  
  What is SSE?
&lt;/h1&gt;

&lt;p&gt;SSE is a simple and efficient way to send real-time updates from a server to a client over an HTTP connection. It is a part of the HTML5 specification and is supported by all modern web browsers. SSE is based on a unidirectional data flow, where the server sends messages to the client, but the client cannot send messages back to the server.&lt;/p&gt;

&lt;p&gt;SSE uses a text-based format known as “Server-Sent Events” to send data to the client. The data is sent as a series of events, each of which contains a message and an optional event type. The event type is used to distinguish between different types of messages and allows the client to handle them differently.&lt;/p&gt;

&lt;h1&gt;
  
  
  How does SSE work?
&lt;/h1&gt;

&lt;p&gt;The SSE protocol works by establishing a persistent HTTP connection between the server and the client. This connection is kept open for as long as the client wants to receive updates from the server. When the server has new data to send, it sends an HTTP response with a special MIME type “text/event-stream”.&lt;/p&gt;

&lt;p&gt;The response contains a series of events, each of which is separated by a new line character (“\n”). Each event has the following format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;event: [event type]\n
data: [message]\n\n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The “event” field is optional and is used to provide a name for the event. The “data” field contains the actual message being sent. The two newline characters at the end of each event are used to signal the end of the event.&lt;/p&gt;

&lt;p&gt;Here’s an example of a simple SSE response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: text/event-stream

event: message
data: Hello, world!

event: message
data: This is a test message.

event: customEvent
data: {"foo": "bar", "baz": 123}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we’re sending three events to the client. The first two events have the event type “message” and contain simple text messages. The third event has the event type “customEvent” and contains a JSON object as its message.&lt;/p&gt;

&lt;p&gt;When the client receives an SSE response, it uses the data to update its user interface. This can be done using JavaScript to manipulate the DOM, for example.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementing SSE
&lt;/h1&gt;

&lt;p&gt;Implementing SSE in your application is relatively straightforward. Here’s an example of how to implement SSE using Node.js and the Express framework:&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;express&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Set up SSE endpoint&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Set headers&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/event-stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cache-Control&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keep-alive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Send initial event&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data: Connected&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Set interval to send periodic events&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;intervalId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data: Hello, world!&lt;/span&gt;&lt;span class="se"&gt;\n\n&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="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Clean up on connection close&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;intervalId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Start server&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server started on port 3000&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we’re setting up an SSE endpoint at “/events”. We’re setting the necessary headers for SSE and sending an initial event to the client to confirm that the connection has been established.&lt;/p&gt;

&lt;p&gt;We’re then setting up an interval to send periodic events to the client every second. Finally, we’re cleaning up the interval when the connection is closed by the client.&lt;/p&gt;

&lt;p&gt;On the client side, we can use the following JavaScript code to listen for SSE events:&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;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we’re creating a new EventSource object and passing in the URL of our SSE endpoint. We’re then listening for the “message” event and logging the data to the console. We’re also listening for the “error” event in case there are any connection issues.&lt;/p&gt;

&lt;p&gt;Note that the &lt;code&gt;EventSource&lt;/code&gt; path on the front end can only be used by &lt;code&gt;GET&lt;/code&gt; requests, if you want to use &lt;code&gt;POST&lt;/code&gt; and other HTTP methods, you need to parse the response data yourself.&lt;/p&gt;

&lt;p&gt;If you want a native Node.js implementation, &lt;a href="https://stackblitz.com/edit/stackblitz-starters-vnmdin?file=index.js&amp;amp;utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=how-server-sent-events-sse-work" rel="noopener noreferrer"&gt;here’s one&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/stackblitz-starters-vnmdin?file=index.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  Use cases for SSE
&lt;/h1&gt;

&lt;p&gt;SSE can be used in a wide range of applications that require real-time updates. Here are a few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Social media platforms: SSE can be used to provide real-time updates for social media platforms, such as notifications of new messages, comments, or likes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Financial applications: SSE can be used to provide real-time updates for financial applications, such as stock prices, currency exchange rates, or news.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Online gaming: SSE can be used to provide real-time updates for online gaming applications, such as notifications of game events, scores, or rankings.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Benefits of using SSE
&lt;/h1&gt;

&lt;p&gt;There are several benefits to using SSE over other real-time communication methods such as polling or WebSockets:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Efficiency&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;SSE uses a persistent HTTP connection, which means that the overhead of establishing and maintaining the connection is much lower than with other methods. This makes SSE more efficient and less resource-intensive, which is especially important when dealing with large numbers of clients.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Simplicity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;SSE is a simple protocol that is easy to understand and implement. It does not require any special libraries or frameworks and can be implemented using standard web technologies such as JavaScript and HTTP.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Reliability&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;SSE is a reliable protocol that provides automatic reconnection in case of a network interruption. This ensures that the client will continue to receive updates even if the connection is temporarily lost.&lt;/p&gt;

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

&lt;p&gt;Server-Sent Events (SSE) are a simple and efficient way to send real-time updates from a server to a client over an HTTP connection. It is a part of the HTML5 specification and is supported by all modern web browsers. SSE uses a unidirectional data flow, where the server sends messages to the client, but the client cannot send messages back to the server. This saves you from constantly polling the server for events, which not only improves performance but also reduces complexity.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you found this helpful, please consider&lt;/em&gt; &lt;em&gt;&lt;a href="https://webdeveloper.beehiiv.com/subscribe?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=under-the-hood-of-react-router-in-40-lines-of-code&amp;amp;_bhlid=2f26f41cf9803691495f3ae68d43e3d616c1c102" rel="noopener noreferrer"&gt;subscribing to my newsletter&lt;/a&gt;&lt;/em&gt; &lt;em&gt;for more useful articles and tools about web development. Thanks for reading!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Ditch dotenv: Node.js Now Natively Supports .env File Loading</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Sun, 22 Sep 2024 08:07:16 +0000</pubDate>
      <link>https://dev.to/zacharylee/ditch-dotenv-nodejs-now-natively-supports-env-file-loading-8e6</link>
      <guid>https://dev.to/zacharylee/ditch-dotenv-nodejs-now-natively-supports-env-file-loading-8e6</guid>
      <description>&lt;p&gt;One of the staples of environment management in Node.js has been the use of the &lt;code&gt;dotenv&lt;/code&gt; package, which facilitates the loading of environment variables from a &lt;code&gt;.env&lt;/code&gt; file. However, recent updates in Node.js have introduced built-in capabilities that may reduce or eliminate the need for external packages like &lt;code&gt;dotenv&lt;/code&gt; for managing environment variables.&lt;/p&gt;

&lt;h1&gt;
  
  
  Native &lt;code&gt;.env&lt;/code&gt; File Handling
&lt;/h1&gt;

&lt;p&gt;Starting from version 20.6.0, Node.js allows the use of the &lt;code&gt;--env-file&lt;/code&gt; flag when executing scripts. This flag specifies a path to an &lt;code&gt;.env&lt;/code&gt; file that Node.js will read before running the specified script. This approach streamlines the process of setting environment variables, making it more integrated and less reliant on third-party packages.&lt;/p&gt;

&lt;p&gt;Consider a scenario where you have the following environment configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .env file&lt;/span&gt;
&lt;span class="s"&gt;NODE_OPTIONS='--title="Sample Node App"'&lt;/span&gt;
&lt;span class="s"&gt;USER_NAME='John Doe'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run a Node.js script using this configuration, you would use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--env-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.env your-script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside &lt;code&gt;your-script.js&lt;/code&gt;, accessing these variables can be done as follows:&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs: Sample Node App&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;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;USER_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs: Hello, John Doe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Simplified Loading with &lt;code&gt;process.loadEnvFile()&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Building upon the initial support, Node.js version 21.7.0 introduced the &lt;code&gt;process.loadEnvFile()&lt;/code&gt; method. This function simplifies the loading of environment variables by incorporating them into the runtime process without the need for command-line flags.&lt;/p&gt;

&lt;p&gt;You can load the environment variables programmatically within your application as shown below:&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;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadEnvFile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Automatically loads `.env` from the current directory&lt;/span&gt;
&lt;span class="err"&gt;​&lt;/span&gt;
&lt;span class="c1"&gt;// Or specify a path&lt;/span&gt;
&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadEnvFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./config/env_vars.env&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;h1&gt;
  
  
  Parsing Environment Variables
&lt;/h1&gt;

&lt;p&gt;In addition to loading environment variables, Node.js 21.7.0 introduced &lt;code&gt;util.parseEnv()&lt;/code&gt;, a utility function that parses a string containing environment variable definitions into an object.&lt;/p&gt;

&lt;p&gt;Here’s how you might use &lt;code&gt;util.parseEnv()&lt;/code&gt;:&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;util&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;node:util&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;envVars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseEnv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API_KEY=12345&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envVars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs: 12345&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Support for Multi-line Values in &lt;code&gt;.env&lt;/code&gt; Files
&lt;/h2&gt;

&lt;p&gt;Another feature in Node.js 21.7.0 is the support for multi-line values in &lt;code&gt;.env&lt;/code&gt; files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;CERTIFICATE="-----BEGIN CERTIFICATE-----&lt;/span&gt;
&lt;span class="s"&gt;MIIDdTCCAl2gAwIBAgIJAKC1hi9s2wfMM...&lt;/span&gt;
&lt;span class="s"&gt;-----END CERTIFICATE-----"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now include such multi-line strings directly in your &lt;code&gt;.env&lt;/code&gt; files, making management of complex configurations cleaner and more straightforward.&lt;/p&gt;

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

&lt;p&gt;The native .env file support introduced in the latest Node.js allows your project to be set up faster and reduces dependencies on external packages such as dotenv.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you found this helpful, please consider&lt;/em&gt; &lt;a href="https://webdeveloper.beehiiv.com/subscribe?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=under-the-hood-of-react-router-in-40-lines-of-code&amp;amp;_bhlid=2f26f41cf9803691495f3ae68d43e3d616c1c102" rel="noopener noreferrer"&gt;&lt;em&gt;subscribing to my newsletter&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for more useful articles and tools about web development. Thanks for reading!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>node</category>
    </item>
    <item>
      <title>How to Create a Type to Retrieve All Keys of an Object in TypeScript</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Mon, 16 Sep 2024 04:30:01 +0000</pubDate>
      <link>https://dev.to/zacharylee/how-to-create-a-type-to-retrieve-all-keys-of-an-object-in-typescript-54dn</link>
      <guid>https://dev.to/zacharylee/how-to-create-a-type-to-retrieve-all-keys-of-an-object-in-typescript-54dn</guid>
      <description>&lt;p&gt;Typescript has a feature called &lt;code&gt;keyof&lt;/code&gt; that can be used to obtain the keys of an object. However, the &lt;code&gt;keyof&lt;/code&gt; operator only works for the first level of an object, and when we want to obtain all keys in a deep level, things get a bit more complicated. In this article, we will discuss how to implement a type that can obtain all keys in a deep level.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Overview of the Problem&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;To understand the problem we are trying to solve, let’s start with an example. Consider the following 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;b&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="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;d&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="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&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;If we want to obtain all the keys of this object, including the keys in the nested objects, we need a type that can recursively traverse the object and return all the keys. This can be a challenging task, especially for complex objects with multiple levels of nesting.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;A Possible Solution&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;One approach to solving this problem is to use a recursive type definition. Typescript allows us to define recursive types using intersection types. An intersection type is a type that represents a value that has all the properties of all the types in the intersection.&lt;/p&gt;

&lt;p&gt;We can define a recursive type that represents an object with a set of keys, where each key is either a primitive value or another object that also has a set of keys. Here’s how we can define this 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;DeepKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;DeepKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This type definition may seem a bit complex, so let’s break it down into smaller parts.&lt;/p&gt;

&lt;p&gt;The type &lt;code&gt;DeepKeys&amp;lt;T&amp;gt;&lt;/code&gt; is a conditional type that checks if the input type &lt;code&gt;T&lt;/code&gt; is an object. If &lt;code&gt;T&lt;/code&gt; is an object, we use a mapped type to create a new object with the same keys as &lt;code&gt;T&lt;/code&gt;, but the values are the keys of the nested objects, represented as a string. If &lt;code&gt;T&lt;/code&gt; is not an object, we return an empty string.&lt;/p&gt;

&lt;p&gt;The mapped type uses the &lt;code&gt;keyof&lt;/code&gt; operator to get the keys of the object, and then we use a conditional statement to check if each key is a string or number. If the key is a string or number, we concatenate it with a dot and the keys of the nested object, obtained recursively using &lt;code&gt;DeepKeys&amp;lt;T[K]&amp;gt;&lt;/code&gt;. If the key is not a string or number, we return &lt;code&gt;never&lt;/code&gt;, which means the key is not valid.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Using the Type&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Now that we have defined the &lt;code&gt;DeepKeys&lt;/code&gt; type, we can use it to get the keys of any object with nested objects. Here's an example of how we can use it:&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;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;b&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="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;d&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="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DeepKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;DeepKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAllKeys&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="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;DeepKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&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;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newPrefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;newPrefix&lt;/span&gt;&lt;span class="p"&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;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;getAllKeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newPrefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;DeepKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getAllKeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ["a" | "f" | "h" | "a.b" | "a.c" | "a.c.d" | "a.c.e" | "f.g"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we define a function called &lt;code&gt;getAllKeys&lt;/code&gt; that takes an object as an argument and returns an array of all the keys in the object. We use the &lt;code&gt;Object.keys&lt;/code&gt; method to get the keys of the object, and then we cast the result to the &lt;code&gt;DeepKeys&lt;/code&gt; type to ensure that we get all the keys, including the keys in the nested objects.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Limitations&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;While the &lt;code&gt;DeepKeys&lt;/code&gt; type can be useful in many situations, it does have some limitations. One limitation is that it only works for objects with a finite depth. If we have an object with an infinite depth, such as an object that contains a reference to itself, the type definition will result in a stack overflow error.&lt;/p&gt;

&lt;p&gt;Another limitation is that the resulting type can be very complex for objects with many levels of nesting, which can make it difficult to work with. In some cases, it may be necessary to use a simpler type definition or a different approach to get the keys of an object.&lt;/p&gt;

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

&lt;p&gt;In this article, we have discussed how to implement a type that can obtain all the keys in an object, including the keys in the nested objects. We have used a recursive type definition to define the &lt;code&gt;DeepKeys&lt;/code&gt; type, which allows us to recursively traverse the object and return all the keys. We have also provided an example of how to use the &lt;code&gt;DeepKeys&lt;/code&gt; type to get the keys of an object.&lt;/p&gt;

&lt;p&gt;While the &lt;code&gt;DeepKeys&lt;/code&gt; type has some limitations, it can be a useful tool for working with objects with nested objects.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this helpful, please consider&lt;/em&gt; &lt;em&gt;&lt;a href="https://webdeveloper.beehiiv.com/subscribe?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=under-the-hood-of-react-router-in-40-lines-of-code&amp;amp;_bhlid=2f26f41cf9803691495f3ae68d43e3d616c1c102" rel="noopener noreferrer"&gt;subscribing to my newsletter&lt;/a&gt;&lt;/em&gt; &lt;em&gt;for more useful articles and tools about web development. Thanks for reading!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>7 Lesser-Known HTML Attributes to Enhance User Experience</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Wed, 11 Sep 2024 04:29:00 +0000</pubDate>
      <link>https://dev.to/zacharylee/7-lesser-known-html-attributes-to-enhance-user-experience-45gm</link>
      <guid>https://dev.to/zacharylee/7-lesser-known-html-attributes-to-enhance-user-experience-45gm</guid>
      <description>&lt;p&gt;HTML is a powerful language for creating web pages, and while most developers are familiar with commonly used HTML attributes, there are several lesser-known attributes that can provide additional functionality and enhance the user experience.&lt;/p&gt;

&lt;h1&gt;
  
  
  1. The &lt;code&gt;enterkeyhint&lt;/code&gt; Attribute for Virtual Keyboards
&lt;/h1&gt;

&lt;p&gt;When designing web forms for mobile devices, it’s important to consider the virtual keyboards that users interact with. The &lt;code&gt;enterkeyhint&lt;/code&gt; attribute is a global attribute that can be applied to form controls or elements with the &lt;code&gt;contenteditable&lt;/code&gt; attribute set to true. It assists users by providing hints to the virtual keyboard about the intended action associated with the "Enter" key. This attribute accepts values such as &lt;code&gt;enter&lt;/code&gt;, &lt;code&gt;done&lt;/code&gt;, &lt;code&gt;go&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;previous&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt;, and &lt;code&gt;send&lt;/code&gt;, allowing you to customize the hint based on the specific context of your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;enterkeyhint=&lt;/span&gt;&lt;span class="s"&gt;"done"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  2. Attributes for Custom Ordered Lists
&lt;/h1&gt;

&lt;p&gt;While working with ordered lists &lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;, you can utilize several lesser-known attributes to customize the behavior of the numbering. These attributes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;reversed&lt;/code&gt; attribute: It allows you to number the list items in reverse order, from high to low instead of the default low to high.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;start&lt;/code&gt; attribute: It defines the number from which the list should start.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;type&lt;/code&gt; attribute: It specifies whether to use numbers, letters, or Roman numerals for the list items.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;value&lt;/code&gt; attribute: It enables you to set a custom number for a specific list item.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ol&lt;/span&gt; &lt;span class="na"&gt;reversed&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;List item...&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;List item...&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;List item...&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ol&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ol&lt;/span&gt; &lt;span class="na"&gt;reversed&lt;/span&gt; &lt;span class="na"&gt;start=&lt;/span&gt;&lt;span class="s"&gt;"20"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Typee: A Peep at Polynesian Life (1846)&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Omoo: A Narrative of Adventures in the South Seas (1847)&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Mardi: and aVoyage Thither (1849)&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Redburn: His First Voyage (1849)&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;White-Jacket; or, The World in a Man-of-War (1850)&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Moby-Dick; or, The Whale (1851)&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Pierre; or, The Ambiguities (1852)&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Isle of the Cross (1853 unpublished, and now lost)&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ol&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  3. The &lt;code&gt;decoding&lt;/code&gt; Attribute for &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; Element
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;decoding&lt;/code&gt; attribute allows you to provide a hint to the browser about how an image should be decoded. This attribute can be added to an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element and accepts three values: &lt;code&gt;sync&lt;/code&gt;, &lt;code&gt;async&lt;/code&gt;, and &lt;code&gt;auto&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;sync&lt;/code&gt;: Decode the image synchronously, which is the default behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;async&lt;/code&gt;: Decode the image asynchronously to avoid delaying the presentation of other content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;auto&lt;/code&gt;: Let the browser use its default decoding method.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/example.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Example"&lt;/span&gt; &lt;span class="na"&gt;decoding=&lt;/span&gt;&lt;span class="s"&gt;"async"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By specifying the appropriate decoding behavior, you can optimize the loading and rendering of images on your web page.&lt;/p&gt;

&lt;h1&gt;
  
  
  4. The &lt;code&gt;loading&lt;/code&gt; Attribute for &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; Element
&lt;/h1&gt;

&lt;p&gt;Similar to lazy loading images, the &lt;code&gt;loading&lt;/code&gt; attribute can be applied to &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; elements to control when the iframe's content should be loaded. By setting the &lt;code&gt;loading&lt;/code&gt; attribute to &lt;code&gt;lazy&lt;/code&gt;, you can defer the loading of the iframe until it's about to enter the viewport. This helps improve performance by reducing the initial page load time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/page.html"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"300"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"250"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  5. The &lt;code&gt;crossorigin&lt;/code&gt; Attribute for Cross-Origin Resource Sharing (CORS)
&lt;/h1&gt;

&lt;p&gt;When working with elements like &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;, you may come across the need for cross-origin resource sharing (CORS). The &lt;code&gt;crossorigin&lt;/code&gt; attribute allows you to specify how the resource should be fetched in terms of CORS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/image.jpg"&lt;/span&gt; &lt;span class="na"&gt;crossorigin=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Example Image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The attribute accepts two values: &lt;code&gt;anonymous&lt;/code&gt; and &lt;code&gt;use-credentials&lt;/code&gt;. Setting it to &lt;code&gt;anonymous&lt;/code&gt; indicates that the resource should be fetched without including user credentials, while &lt;code&gt;use-credentials&lt;/code&gt; indicates that the user credentials should be included.&lt;/p&gt;

&lt;h1&gt;
  
  
  6. The &lt;code&gt;disablepictureinpicture&lt;/code&gt; Attribute for &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; Element
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;disablepictureinpicture&lt;/code&gt; attribute can be applied to the &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element to disable the Picture-in-Picture (PiP) feature. PiP allows videos to be displayed in a floating window, but if you want to prevent this behavior, you can simply add the attribute to the video element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;video&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"example.mp4"&lt;/span&gt; &lt;span class="na"&gt;disablepictureinpicture&lt;/span&gt; &lt;span class="na"&gt;controls&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/video&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  7. The &lt;code&gt;integrity&lt;/code&gt; Attribute for Scripts
&lt;/h1&gt;

&lt;p&gt;To ensure that external scripts haven’t been tampered with, you can make use of the &lt;code&gt;integrity&lt;/code&gt; attribute. This attribute allows you to provide a cryptographic hash value that the browser can use to verify the integrity of the script file before executing it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt; &lt;span class="na"&gt;integrity=&lt;/span&gt;&lt;span class="s"&gt;"sha256-Kx70Z9jzvYF0Eex8oO7w08="&lt;/span&gt; &lt;span class="na"&gt;crossorigin=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By including the &lt;code&gt;integrity&lt;/code&gt; attribute with the appropriate hash value, you can add an extra layer of security to ensure the script's authenticity.&lt;/p&gt;

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

&lt;p&gt;In this article, we have explored a collection of lesser-known HTML attributes that can enhance your web development projects. From improving user interactions to optimizing resource loading, these attributes provide valuable functionalities that may not be widely known or utilized.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you find this helpful, please &lt;strong&gt;&lt;a href="https://webdeveloper.beehiiv.com/?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=7-lesser-known-html-attributes-to-enhance-user-experience" rel="noopener noreferrer"&gt;&lt;em&gt;consider subscribing&lt;/em&gt;&lt;/a&gt;&lt;/strong&gt;_for more useful articles and tools about web development. Thanks for reading!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Difference Between new Function() and new function() in JavaScript</title>
      <dc:creator>Zach</dc:creator>
      <pubDate>Tue, 10 Sep 2024 13:42:14 +0000</pubDate>
      <link>https://dev.to/zacharylee/difference-between-new-function-and-new-function-in-javascript-254a</link>
      <guid>https://dev.to/zacharylee/difference-between-new-function-and-new-function-in-javascript-254a</guid>
      <description>&lt;p&gt;JavaScript is indeed flexible, but it also brings some confusion. For example, you can use multiple ways to do the same thing, such as creating functions, objects, etc. So what is the difference between the two mentioned in the title?&lt;/p&gt;




&lt;p&gt;&lt;code&gt;new Function&lt;/code&gt; is another way to create a function, its syntax:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const func = new Function ([arg1, arg2, ...argN], functionBody);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A simple example:&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;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;return a + b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, this gives great flexibility. It’s not common, but there are some cases where it can be used. For example, we can use it when we need to dynamically compile a template into a function, which is what Vue.js does as far as I know. Besides that, it can also be used if we need to receive code strings from the server to create functions dynamically.&lt;/p&gt;

&lt;p&gt;Let’s quickly talk about its features. See what the code below will output?&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;globalThis&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;10&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;createFunction1&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;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;return a;&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;function&lt;/span&gt; &lt;span class="nf"&gt;createFunction2&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;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;f1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createFunction1&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;f1&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;f2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createFunction2&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// ?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The answer is &lt;code&gt;10&lt;/code&gt; and &lt;code&gt;20&lt;/code&gt;. This is because &lt;code&gt;new Function&lt;/code&gt; always creates functions in the global scope. Only global variables and their own local variables can be accessed when running them.&lt;/p&gt;




&lt;p&gt;Whereas &lt;code&gt;new function()&lt;/code&gt; is intended to create a new object and apply an anonymous function as a constructor. Such as the following example:&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;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// { name: 1 }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. Actually, every JavaScript function is a &lt;code&gt;Function&lt;/code&gt; object, in other words, &lt;code&gt;(function () {}).constructor === Function&lt;/code&gt; returns &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An associated knowledge point is how to use &lt;code&gt;new Function()&lt;/code&gt; to create an asynchronous function? &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=difference-between-new-function-and-new-function-in-javascript" rel="noopener noreferrer"&gt;MDN&lt;/a&gt; gave us the answer:&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="c1"&gt;// Since `AsyncFunction` is not a global object, we need to get it manually:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AsyncFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="kd"&gt;constructor&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;fetchURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AsyncFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;return await fetch(url);&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;fetchURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;If you found this helpful, please consider&lt;/em&gt; &lt;a href="https://webdeveloper.beehiiv.com/subscribe?utm_source=webdeveloper.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=under-the-hood-of-react-router-in-40-lines-of-code&amp;amp;_bhlid=2f26f41cf9803691495f3ae68d43e3d616c1c102" rel="noopener noreferrer"&gt;&lt;em&gt;subscribing to my newsletter&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for more useful articles and tools about web development. Thanks for reading!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
