<?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: Renato Rodrigues</title>
    <description>The latest articles on DEV Community by Renato Rodrigues (@rerodrigues).</description>
    <link>https://dev.to/rerodrigues</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%2F622082%2F6941f825-4139-4ba4-9b93-dfdfc9f30173.jpg</url>
      <title>DEV Community: Renato Rodrigues</title>
      <link>https://dev.to/rerodrigues</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rerodrigues"/>
    <language>en</language>
    <item>
      <title>Free, self-hosted, instant Nx remote cache with Docker and Cacheiro Instants. Ready for S3, GCS, Azure and disk</title>
      <dc:creator>Renato Rodrigues</dc:creator>
      <pubDate>Thu, 29 Oct 2026 17:49:46 +0000</pubDate>
      <link>https://dev.to/rerodrigues/free-self-hosted-instant-nx-remote-cache-with-docker-and-cacheiro-instants-ready-for-s3-gcs-21c3</link>
      <guid>https://dev.to/rerodrigues/free-self-hosted-instant-nx-remote-cache-with-docker-and-cacheiro-instants-ready-for-s3-gcs-21c3</guid>
      <description>&lt;p&gt;If you maintain a monorepo with Nx or Lerna, you know how much remote caching helps: whatever a developer or a CI job has already built doesn't need to be built again by anyone else. The problem is where to host that cache without paying for a managed service and without building a server from scratch.&lt;/p&gt;

&lt;p&gt;That's where &lt;strong&gt;Cacheiro&lt;/strong&gt; comes in: a free, open source remote cache server for Nx and Lerna. And with the new &lt;strong&gt;Cacheiro Instants&lt;/strong&gt; feature, spinning up one of these servers is now a single &lt;code&gt;docker run&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this post I'll cover where Cacheiro Instants came from, what it delivers and how to use each of the four variants.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://rerodrigues.github.io/nx-remote-cache-server/" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt; is a self-hosted, open source (MIT) server that implements the Nx remote cache OpenAPI specification. It works with Nx and Lerna (which relies on Nx for task orchestration), it's modular, and it has four storage backends: filesystem, Amazon S3, Google Cloud Storage and Azure Blob Storage.&lt;/p&gt;

&lt;p&gt;Why does it exist? Nx deprecated its official self-hosted cache packages after &lt;a href="https://www.cve.org/CVERecord?id=CVE-2025-36852" rel="noopener noreferrer"&gt;CVE-2025-36852&lt;/a&gt;, a critical cache poisoning vulnerability, and left two alternatives: its paid service or building your own server. Cacheiro is my answer to the second one, built to be reused by anyone. The full story is in the &lt;a href="https://dev.to/rerodrigues/creating-your-own-remote-cache-server-for-nx-and-lerna-with-cacheiro-2dcg"&gt;launch article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To make your workspace use the server, you only need to set two environment variables (the token is optional):&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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NX_SELF_HOSTED_REMOTE_CACHE_SERVER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://mycache.server"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-secure-token-here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And run your usual commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx run-many &lt;span class="nt"&gt;-t&lt;/span&gt; build
&lt;span class="c"&gt;# or&lt;/span&gt;
lerna run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The motivation: from library to ready-made image
&lt;/h2&gt;

&lt;p&gt;Originally, Cacheiro was distributed only as a &lt;strong&gt;library&lt;/strong&gt;. It could be embedded into existing systems and customized freely. That philosophy gives developers freedom, but it creates extra work for people who just want to use the cache server, especially DevOps teams.&lt;/p&gt;

&lt;h3&gt;
  
  
  The first step: Cacheiro Runner
&lt;/h3&gt;

&lt;p&gt;To reduce that friction, the project already offered &lt;strong&gt;Cacheiro Runner&lt;/strong&gt;, a ready-to-use example application that runs Cacheiro. It loads the configuration, validates it, creates the store and starts the server. But Cacheiro Runner is an opinionated implementation, meant to serve as a reference: to use S3, GCS or Azure, for example, you have to edit the source code and adjust the Dockerfile.&lt;/p&gt;

&lt;h3&gt;
  
  
  The solution: Cacheiro Instants ⚡
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cacheiro Instants&lt;/strong&gt; is exactly the missing step: &lt;strong&gt;100% ready-to-use&lt;/strong&gt; Docker images, in four flavors (&lt;code&gt;fs&lt;/code&gt;, &lt;code&gt;s3&lt;/code&gt;, &lt;code&gt;gcs&lt;/code&gt; and &lt;code&gt;azure&lt;/code&gt;). You run the image in your CI or on your infrastructure, pass a parameter or two, and that's it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No build, no code configuration, no custom deploy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The images live on the GitHub Container Registry (GHCR):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flavor&lt;/th&gt;
&lt;th&gt;Image&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Filesystem&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ghcr.io/rerodrigues/cacheiro-instants-fs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon S3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ghcr.io/rerodrigues/cacheiro-instants-s3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Cloud Storage&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ghcr.io/rerodrigues/cacheiro-instants-gcs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Blob Storage&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ghcr.io/rerodrigues/cacheiro-instants-azure&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each image includes only the store package and the cloud SDK for its own flavor. The &lt;code&gt;fs&lt;/code&gt; image, for example, carries no AWS, Google or Azure SDK.&lt;/p&gt;

&lt;p&gt;The full documentation for every environment variable is on the &lt;a href="https://rerodrigues.github.io/nx-remote-cache-server/packages/instants" rel="noopener noreferrer"&gt;Cacheiro Instants page&lt;/a&gt; of the project site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting it running
&lt;/h2&gt;

&lt;p&gt;All flavors share the same base configuration: port &lt;code&gt;3000&lt;/code&gt; and host &lt;code&gt;0.0.0.0&lt;/code&gt; are already set in the image, and authentication is done with a bearer token in &lt;code&gt;CACHEIRO_AUTH_TOKEN&lt;/code&gt;. If you don't set the token, authentication is disabled, so always set one in exposed environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Filesystem (&lt;code&gt;fs&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The simplest option to get started, or for a single server. Data lives in &lt;code&gt;/cache&lt;/code&gt;, which you mount as a volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CACHEIRO_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-secret-token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/cache:/cache &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/rerodrigues/cacheiro-instants-fs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this flavor, artifacts expire after 7 days by default (&lt;code&gt;CACHEIRO_CACHE_TTL_DAYS&lt;/code&gt;, and &lt;code&gt;0&lt;/code&gt; disables expiration).&lt;/p&gt;

&lt;h3&gt;
  
  
  Amazon S3 (&lt;code&gt;s3&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;It works with S3 and also with compatible alternatives such as MinIO, LocalStack, Cloudflare R2 and DigitalOcean Spaces (via &lt;code&gt;S3_ENDPOINT&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CACHEIRO_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-secret-token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;S3_BUCKET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-nx-cache &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;S3_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;... &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;... &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/rerodrigues/cacheiro-instants-s3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Google Cloud Storage (&lt;code&gt;gcs&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Credentials follow Google's standard mechanisms (service account file or workload identity):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CACHEIRO_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-secret-token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;GCS_BUCKET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-nx-cache &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/gcp-credentials.json:/creds.json:ro &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;GOOGLE_APPLICATION_CREDENTIALS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/creds.json &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/rerodrigues/cacheiro-instants-gcs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Azure Blob Storage (&lt;code&gt;azure&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CACHEIRO_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-secret-token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;AZURE_CONTAINER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-nx-cache &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;AZURE_STORAGE_CONNECTION_STRING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/rerodrigues/cacheiro-instants-azure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of the connection string, you can also use &lt;code&gt;AZURE_ACCOUNT_NAME&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features worth highlighting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Read-only token.&lt;/strong&gt; With &lt;code&gt;CACHEIRO_AUTH_READ_ONLY_TOKEN&lt;/code&gt; you create a second token that only allows reads (GET). A common pattern is to give the full-access token only to the main branch CI, and the read-only one to developer machines and PRs. There's a &lt;a href="https://rerodrigues.github.io/nx-remote-cache-server/blog/auth-tokens" rel="noopener noreferrer"&gt;post on the project site&lt;/a&gt; that goes deeper into this fine-grained token control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Built-in healthcheck.&lt;/strong&gt; The images ship with a Docker &lt;code&gt;HEALTHCHECK&lt;/code&gt; that queries the server's &lt;code&gt;/health&lt;/code&gt; endpoint. It follows the port and TLS settings you configured, and it doesn't install anything extra in the image. The result shows up right in &lt;code&gt;docker ps&lt;/code&gt;, and orchestrators like Docker Compose can use it to know when the cache is ready:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;span class="c"&gt;# STATUS: Up 2 minutes (healthy)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Clear configuration errors.&lt;/strong&gt; All configuration comes from environment variables and is validated before the server starts. If something required is missing or invalid, the container fails right away and lists all the problems at once, instead of making you find them one by one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Native HTTPS.&lt;/strong&gt; To enable TLS in any flavor, point to the certificate and key and mount them as a read-only volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CACHEIRO_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-secret-token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CACHEIRO_TLS_CERT_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/certs/cert.pem &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CACHEIRO_TLS_KEY_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/certs/key.pem &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/certs:/certs:ro &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/rerodrigues/cacheiro-instants-fs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Always up to date, predictably versioned
&lt;/h2&gt;

&lt;p&gt;This was one of my priorities. Whenever any package in the Cacheiro ecosystem gets a new version, the corresponding images are updated too.&lt;/p&gt;

&lt;p&gt;There are two kinds of tags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Version tag&lt;/strong&gt; (for example, &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server/pkgs/container/cacheiro-instants-s3/1464024326?tag=0.4.0" rel="noopener noreferrer"&gt;&lt;code&gt;0.4.0&lt;/code&gt;&lt;/a&gt;): follows the version of the &lt;code&gt;@renatorodrigues/cacheiro-instants&lt;/code&gt; package and never changes once published. It's the one to use in production, because it guarantees the same image today and six months from now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;latest&lt;/code&gt;&lt;/strong&gt;: points to the newest build of each flavor. Great for trying things out, but it can change without notice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To pin the version in production:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull ghcr.io/rerodrigues/cacheiro-instants-s3:0.4.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two more details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each flavor is published independently, so only the flavor whose store changed gets a new &lt;code&gt;latest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The images are multi-architecture (amd64 and arm64), which helps people developing on Apple Silicon Macs and running on ARM instances.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Runner or Instants: which one should you pick?
&lt;/h2&gt;

&lt;p&gt;My recommendation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Just want a cache server up and running?&lt;/strong&gt; Use &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server/tree/main/packages/cacheiro-instants" rel="noopener noreferrer"&gt;&lt;strong&gt;Cacheiro Instants&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Want to customize the behavior, write your own store or embed the server in another application?&lt;/strong&gt; Use the &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server/tree/main/packages/cacheiro" rel="noopener noreferrer"&gt;Cacheiro library&lt;/a&gt;, with &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server/tree/main/packages/cacheiro-runner" rel="noopener noreferrer"&gt;&lt;strong&gt;Cacheiro Runner&lt;/strong&gt;&lt;/a&gt; as a starting point.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing locally before going to the cloud
&lt;/h2&gt;

&lt;p&gt;The repository includes local emulators for S3, GCS and Azure Blob, so you can test each store without creating any real cloud resources. The instructions are in the &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server#local-emulators" rel="noopener noreferrer"&gt;emulators section of the README&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Remote caching shouldn't require an infrastructure project. With Cacheiro Instants, the path to a shared CI cache has three steps: pick a flavor, set a few environment variables and run a container.&lt;/p&gt;

&lt;p&gt;If you use Nx or Lerna, give it a try. Pick the flavor that fits your infrastructure, start the container and run your build twice: the second run is the one that shows the value.&lt;/p&gt;

&lt;p&gt;If the project helped you, leave a star on the repository, open an issue with suggestions or bugs, or tell me in the comments which flavor you'd use and why. Feedback is what moves Cacheiro forward the most.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cacheiro repository: &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;https://github.com/rerodrigues/nx-remote-cache-server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cacheiro Instants: &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server/tree/main/packages/cacheiro-instants" rel="noopener noreferrer"&gt;https://github.com/rerodrigues/nx-remote-cache-server/tree/main/packages/cacheiro-instants&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cacheiro Runner: &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server/tree/main/packages/cacheiro-runner" rel="noopener noreferrer"&gt;https://github.com/rerodrigues/nx-remote-cache-server/tree/main/packages/cacheiro-runner&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cacheiro site and documentation: &lt;a href="https://rerodrigues.github.io/nx-remote-cache-server/" rel="noopener noreferrer"&gt;https://rerodrigues.github.io/nx-remote-cache-server/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cacheiro Instants page on the site: &lt;a href="https://rerodrigues.github.io/nx-remote-cache-server/packages/instants" rel="noopener noreferrer"&gt;https://rerodrigues.github.io/nx-remote-cache-server/packages/instants&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cacheiro launch article: &lt;a href="https://dev.to/rerodrigues/creating-your-own-remote-cache-server-for-nx-and-lerna-with-cacheiro-2dcg"&gt;https://dev.to/rerodrigues/creating-your-own-remote-cache-server-for-nx-and-lerna-with-cacheiro-2dcg&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nx</category>
      <category>docker</category>
      <category>devops</category>
      <category>monorepo</category>
    </item>
    <item>
      <title>How I automated npm dependency upgrades with an AI skill</title>
      <dc:creator>Renato Rodrigues</dc:creator>
      <pubDate>Sun, 25 Oct 2026 23:50:27 +0000</pubDate>
      <link>https://dev.to/rerodrigues/how-i-automated-npm-dependency-upgrades-with-an-ai-skill-6np</link>
      <guid>https://dev.to/rerodrigues/how-i-automated-npm-dependency-upgrades-with-an-ai-skill-6np</guid>
      <description>&lt;p&gt;Upgrading dependencies is one of those chores everyone knows they have to do and almost nobody wants to. Read the changelog, figure out what breaks, check whether it affects your project, adjust the code, run the tests. Repeat for every package.&lt;/p&gt;

&lt;p&gt;This post tells how I turned that annoyance into a personal tool and, step by step, into an &lt;strong&gt;AI agent skill&lt;/strong&gt; that now does the job end to end: &lt;a href="https://github.com/rerodrigues/breaking-changes-analyzer" rel="noopener noreferrer"&gt;breaking-changes-analyzer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The goal here is not to teach you how to use the skill (the README does that), but to show the &lt;strong&gt;thought process&lt;/strong&gt; that led to it.&lt;/p&gt;

&lt;p&gt;Each step was born from a limitation of the previous one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The inspiration: prompts saved as Gems
&lt;/h2&gt;

&lt;p&gt;On my personal Gemini account I keep several pre-saved prompts as &lt;strong&gt;Gems&lt;/strong&gt;: one to translate and help me fill in documents, another to check my grammar and adjust the tone to the context, another to summarize long articles and point out the key takeaways.&lt;/p&gt;

&lt;p&gt;They are small tools, each built for a recurring task. And that's where the idea came from.&lt;/p&gt;

&lt;h2&gt;
  
  
  The motivation: breaking changes, over and over
&lt;/h2&gt;

&lt;p&gt;In my day-to-day work I constantly upgrade dependency versions, and with every upgrade I have to check for &lt;em&gt;breaking changes&lt;/em&gt;. It's repetitive work with a predictable shape: read a long text and extract only what matters.&lt;/p&gt;

&lt;p&gt;That was exactly what my article-summarizing Gem already did.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first tool: a Gem
&lt;/h2&gt;

&lt;p&gt;Starting from the summarizer Gem, I built another one that took &lt;strong&gt;two versions of a dependency&lt;/strong&gt;, read both changelogs and pointed out the breaking changes between them. The report had this structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;package name and compared versions;&lt;/li&gt;
&lt;li&gt;breaking changes, grouped;&lt;/li&gt;
&lt;li&gt;important (non-breaking) changes;&lt;/li&gt;
&lt;li&gt;new features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first it worked well. I got a lean report with only what was relevant. But two problems became obvious:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It couldn't see my project.&lt;/strong&gt; Without access to my files and environment, there was no way to tell whether a breaking change was actually a breaking change &lt;em&gt;for me&lt;/em&gt;. The classic example: "dropped support for Node 18" means nothing if your project already runs on Node 24.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It was an isolated web tool.&lt;/strong&gt; It didn't run in my IDE and didn't talk to my agents.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The first skill: getting access to the project
&lt;/h2&gt;

&lt;p&gt;Both problems pointed to the same solution: bring the tool into the development environment.&lt;/p&gt;

&lt;p&gt;I started converting the Gem into a &lt;strong&gt;skill&lt;/strong&gt;, and the conversion brought features the web version could never have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reading the dependency's current version straight from &lt;code&gt;package.json&lt;/code&gt;, so I don't have to provide it;&lt;/li&gt;
&lt;li&gt;cross-checking the upgrade against what the project declares (&lt;code&gt;engines&lt;/code&gt;, peer dependencies, other tools that cap the package version) and flagging real compatibility blockers;&lt;/li&gt;
&lt;li&gt;saving the report to disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usage ended up like this:&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;# From the package.json version to the latest on npm&lt;/span&gt;
/breaking-changes-analyzer chalk

&lt;span class="c"&gt;# Between two specific versions&lt;/span&gt;
/breaking-changes-analyzer chalk 4.1.2 5.3.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Monorepos: where the problem gets interesting
&lt;/h2&gt;

&lt;p&gt;With access to the project's manifests, a new need showed up: handling regular repositories &lt;strong&gt;and&lt;/strong&gt; monorepos.&lt;/p&gt;

&lt;p&gt;Picture the scenario. You ask the skill to check an upgrade for a dependency, but it exists in several monorepo packages, including the root one. Which ones should it check? All of them? What's the minimum version to consider? And the maximum? Can the same maximum be used in every package, or do each package's requirements (Node version, ESM only, etc.) call for different versions? And how do you display all of that: grouped or not?&lt;/p&gt;

&lt;p&gt;After weighing the options, I settled on a &lt;strong&gt;semi-grouped&lt;/strong&gt; report: information common to all packages is grouped into a single section, and smaller sections highlight the packages whose minimum or maximum versions differ from the common ones.&lt;/p&gt;

&lt;p&gt;It was already better, but there was still a long way to go.&lt;/p&gt;

&lt;h2&gt;
  
  
  The upgrade plan
&lt;/h2&gt;

&lt;p&gt;If the skill already knew what the breaking changes were, and already knew my project's versions and constraints, why not ask it to write an &lt;strong&gt;upgrade plan&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;I wrote that part and also asked it to look for &lt;em&gt;migration guides&lt;/em&gt; and any official documentation about the migration, beyond the changelogs.&lt;/p&gt;

&lt;p&gt;It was a good idea, but the result was still just a report (and the analysis remains strictly read-only: nothing was modified). I still had to carry everything out myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  From analysis to execution
&lt;/h2&gt;

&lt;p&gt;By then the next step seemed obvious. After showing the plan, the skill asks whether you want it to carry it out itself.&lt;/p&gt;

&lt;p&gt;Say yes, and it updates the manifests, installs the dependencies, applies the migration plan and runs the project's typecheck, lint and tests to make sure everything still works. In a few minutes. It never commits or pushes: that stays up to you.&lt;/p&gt;

&lt;p&gt;So there are two clearly separate stages: &lt;strong&gt;analysis&lt;/strong&gt; (read-only) and &lt;strong&gt;upgrade&lt;/strong&gt; (only after your "yes").&lt;/p&gt;

&lt;h3&gt;
  
  
  Widening the scope: the dependency's ecosystem
&lt;/h3&gt;

&lt;p&gt;Execution worked well, but there was a gap. Many dependencies belong to an &lt;strong&gt;ecosystem&lt;/strong&gt; (plugins, presets, companion dependencies), and the skill only upgraded the main dependency.&lt;/p&gt;

&lt;p&gt;I taught the skill that, whenever it upgrades a dependency, it should consult its knowledge base to find out which other dependencies belong to the same ecosystem and upgrade them to the &lt;strong&gt;highest compatible version&lt;/strong&gt; with the package being upgraded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Side effect: the cooldown period
&lt;/h3&gt;

&lt;p&gt;Widening the scope caused an unexpected problem. The skill started trying to install versions that were still inside the &lt;em&gt;cooldown&lt;/em&gt; period configured in &lt;code&gt;.npmrc&lt;/code&gt; (the minimum release age policy that protects against freshly published versions), and the install failed.&lt;/p&gt;

&lt;p&gt;The fix was to respect that setting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for &lt;strong&gt;related&lt;/strong&gt; dependencies, the skill always respects the cooldown;&lt;/li&gt;
&lt;li&gt;for the &lt;strong&gt;main&lt;/strong&gt; dependency, if the requested version is still inside the period, it asks whether you want to continue.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The leftovers: cleaning up what's left behind
&lt;/h2&gt;

&lt;p&gt;Once the plan is executed (that is, only if you answered "yes" in the previous stage), almost everything was perfect. Almost. Leftovers from the old version remained: unused config files, residual settings, dependencies that were no longer needed, references to old procedures.&lt;/p&gt;

&lt;p&gt;On top of that, the usage of the new version didn't always take the best advantage of what it offers.&lt;/p&gt;

&lt;p&gt;So I added one more step: a &lt;strong&gt;post-migration audit&lt;/strong&gt; that looks for those leftovers (and improvement opportunities in the new version), always pointing to the file where each one was found, and asks which of them you want to apply. Only what you choose is applied, followed by another round of tests.&lt;/p&gt;

&lt;p&gt;A report is generated at the end, regardless of your answer to the plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  The complete cycle
&lt;/h2&gt;

&lt;p&gt;Looking back, today's skill does the following, in this order.&lt;/p&gt;

&lt;p&gt;Stage 1, &lt;strong&gt;analysis&lt;/strong&gt; (read-only):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;finds the current version (in monorepos there can be more than one) and the target version;&lt;/li&gt;
&lt;li&gt;reads changelogs, releases and migration guides;&lt;/li&gt;
&lt;li&gt;flags the breaking changes and compatibility blockers that matter to your project;&lt;/li&gt;
&lt;li&gt;writes the upgrade plan.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stage 2, &lt;strong&gt;upgrade&lt;/strong&gt;, only if you answer "yes" to the plan:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;executes the plan and runs the tests;&lt;/li&gt;
&lt;li&gt;audits the leftovers and suggests improvements, applying only what you choose.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At the end, in any case, you get the report.&lt;/p&gt;

&lt;p&gt;To install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add rerodrigues/breaking-changes-analyzer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The future: planner and executor
&lt;/h2&gt;

&lt;p&gt;The skill works far beyond what I imagined when I started, and that made me think of something else: what if I split it in two?&lt;/p&gt;

&lt;p&gt;One would &lt;strong&gt;analyze and generate the report&lt;/strong&gt; (the planner). The other would &lt;strong&gt;read that report as input and execute the upgrade&lt;/strong&gt; (the executor). It would be a cleaner separation of responsibilities.&lt;/p&gt;

&lt;p&gt;For now it remains an idea for the future, and everything stays in a single skill.&lt;/p&gt;

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

&lt;p&gt;It all started with a prompt saved in a Gem. Each limitation I found became the next step: lack of access to the project led to the skill, the monorepo led to the semi-grouped report, the report led to the plan, the plan led to execution, and execution led to cleanup.&lt;/p&gt;

&lt;p&gt;If there's a lesson here, it's that &lt;strong&gt;a very small personal tool can grow a lot if you keep asking "what if it also did X?"&lt;/strong&gt;, as long as every step solves a real problem you felt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Now I want to hear from you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How do you manage dependency upgrades?&lt;/strong&gt; Dependabot, Renovate, everything by hand, a fixed day of the week, or only when something breaks?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What's the worst breaking change you've ever faced?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What would you like a tool like this to do that it doesn't do yet?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tell me in the comments. One of those answers might become the skill's next step.&lt;/p&gt;

&lt;p&gt;And if you want to go beyond the conversation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try it.&lt;/strong&gt; Installation takes one command, and the analysis is read-only, so there's no risk of touching your project before you approve anything:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  npx skills add rerodrigues/breaking-changes-analyzer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contribute.&lt;/strong&gt; Found a bug, a monorepo case that doesn't work, or have an idea (maybe the planner/executor split)? Open an issue or a pull request on the &lt;a href="https://github.com/rerodrigues/breaking-changes-analyzer" rel="noopener noreferrer"&gt;repository&lt;/a&gt;. And if the skill saved you a few hours, a star helps other people find it.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>npm</category>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How to Prevent Cache Poisoning in Nx and Lerna Monorepos</title>
      <dc:creator>Renato Rodrigues</dc:creator>
      <pubDate>Wed, 14 Oct 2026 00:57:45 +0000</pubDate>
      <link>https://dev.to/rerodrigues/how-to-prevent-cache-poisoning-in-nx-and-lerna-monorepos-5f5g</link>
      <guid>https://dev.to/rerodrigues/how-to-prevent-cache-poisoning-in-nx-and-lerna-monorepos-5f5g</guid>
      <description>&lt;p&gt;Remote caching is one of the most effective ways to speed up monorepo build pipelines in Nx and Lerna. By caching task results and build artifacts, developers and CI runners avoid re-running unchanged tasks.&lt;/p&gt;

&lt;p&gt;However, sharing a single read/write token across every environment introduces a subtle but significant security threat: &lt;strong&gt;cache poisoning&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this post, we'll look at the risk behind &lt;a href="https://www.cve.org/CVERecord?id=CVE-2025-36852" rel="noopener noreferrer"&gt;CVE-2025-36852 (CREEP)&lt;/a&gt; and show how read-only tokens mitigate it in &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt;, a self-hosted remote cache server for Nx and Lerna.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Security Risk: Shared Access Tokens in CI/CD
&lt;/h2&gt;

&lt;p&gt;CREEP is the reason Nx deprecated its official self-hosted cache packages in May 2026. The core problem: if anyone who can run a build can also write to the shared cache, a malicious build can plant artifacts that other developers and CI jobs will later trust.&lt;/p&gt;

&lt;p&gt;In a typical team or open-source workflow, pull requests trigger automated tests and builds. If your remote cache relies on a single token for both reading and writing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A pull request introduces modified build logic or a malicious dependency.&lt;/li&gt;
&lt;li&gt;The CI pipeline runs the build and uploads the resulting artifact to the remote cache under the task hash.&lt;/li&gt;
&lt;li&gt;Nx task hashes are derived from task inputs, so an attacker can compute the hash that &lt;code&gt;main&lt;/code&gt; will later compute for the same inputs and upload a crafted artifact under it. Cacheiro (like any content-addressed cache) refuses to overwrite an existing hash with a &lt;code&gt;409&lt;/code&gt;, which means the first write wins and a planted artifact stays in place until it expires.&lt;/li&gt;
&lt;li&gt;When &lt;code&gt;main&lt;/code&gt; (or another developer) runs the same task, it downloads and uses the poisoned artifact straight from the remote cache.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The fix is to decouple read and write capabilities, so untrusted code can consume the cache but never populate it.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Preventing Cache Poisoning with Read-Only Tokens
&lt;/h2&gt;

&lt;p&gt;Cacheiro supports a dedicated read-only token (available since &lt;code&gt;cacheiro&lt;/code&gt; 1.3.0):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;GET&lt;/code&gt; requests&lt;/strong&gt; (downloading cached task outputs) are allowed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;PUT&lt;/code&gt; requests&lt;/strong&gt; (uploading new task outputs) are rejected with &lt;code&gt;403 Forbidden&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A missing or unknown token gets &lt;code&gt;401 Unauthorized&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The read-only token has a few rules, all enforced at startup. It requires the regular &lt;code&gt;auth.token&lt;/code&gt; to be set, it must differ from it, and it must not be empty. Otherwise the server refuses to start.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Configuration
&lt;/h3&gt;

&lt;p&gt;With the Docker images, set both tokens through environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CACHEIRO_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"super-secret-write-token"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CACHEIRO_AUTH_READ_ONLY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"read-only-token"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/cache:/cache &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/rerodrigues/cacheiro-instants-fs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using Cacheiro as a library, set them in the &lt;code&gt;auth&lt;/code&gt; object. Both are single strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CacheiroConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@renatorodrigues/cacheiro&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;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CacheiroConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;port&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="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;super-secret-write-token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;readOnlyToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read-only-token&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Client Configuration
&lt;/h3&gt;

&lt;p&gt;Nx and Lerna send whatever token is set in &lt;code&gt;NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN&lt;/code&gt;, and find the server through &lt;code&gt;NX_SELF_HOSTED_REMOTE_CACHE_SERVER&lt;/code&gt;. Give the write token only to trusted pipelines (main branch, releases) and the read-only token to untrusted ones (pull requests).&lt;/p&gt;

&lt;p&gt;Trusted workflow, can read and write:&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;# .github/workflows/main.yml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;NX_SELF_HOSTED_REMOTE_CACHE_SERVER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ vars.CACHEIRO_URL }}&lt;/span&gt;
    &lt;span class="na"&gt;NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CACHEIRO_AUTH_TOKEN }}&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx nx run-many --target=build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pull request workflow, can only read:&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;# .github/workflows/pr-check.yml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;NX_SELF_HOSTED_REMOTE_CACHE_SERVER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ vars.CACHEIRO_URL }}&lt;/span&gt;
    &lt;span class="na"&gt;NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CACHEIRO_READ_ONLY_TOKEN }}&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx nx run-many --target=build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unmerged or untrusted code can now read existing cache entries to save time, but can never inject new artifacts into the shared cache.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep the write token out of reach
&lt;/h3&gt;

&lt;p&gt;A read-only token only helps if untrusted jobs never see the write token:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store the write token only in secrets that PR workflows cannot access, and keep it out of any workflow that runs code from forks.&lt;/li&gt;
&lt;li&gt;Be careful with &lt;code&gt;pull_request_target&lt;/code&gt; and similar triggers that run with repository secrets.&lt;/li&gt;
&lt;li&gt;Serve Cacheiro over HTTPS when it is reachable from outside a private network. Set &lt;code&gt;CACHEIRO_TLS_CERT_FILE&lt;/code&gt; and &lt;code&gt;CACHEIRO_TLS_KEY_FILE&lt;/code&gt;, or &lt;code&gt;server.tls&lt;/code&gt; in library config.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Frictionless Local Development (Optional Auth)
&lt;/h2&gt;

&lt;p&gt;Strong authentication is recommended for shared pipelines, but forcing token setup on an isolated local environment adds friction. In Cacheiro, authentication is optional (since &lt;code&gt;cacheiro&lt;/code&gt; 1.4.0).&lt;/p&gt;

&lt;p&gt;With the Docker images, leave out &lt;code&gt;CACHEIRO_AUTH_TOKEN&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/cache:/cache &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/rerodrigues/cacheiro-instants-fs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the library, leave out the &lt;code&gt;auth&lt;/code&gt; 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;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CacheiroConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;port&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="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;127.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// no `auth`: requests are accepted without a token&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few details worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting &lt;code&gt;auth.readOnlyToken&lt;/code&gt; without &lt;code&gt;auth.token&lt;/code&gt; is an error, so you cannot end up with a read-only token on an open server.&lt;/li&gt;
&lt;li&gt;The reference runner (&lt;code&gt;cacheiro-runner&lt;/code&gt;) ships with a default &lt;code&gt;auth.token&lt;/code&gt; of &lt;code&gt;change-me&lt;/code&gt;, so omitting the variable there does not turn auth off. Change the token instead.&lt;/li&gt;
&lt;li&gt;Passing an empty string as the token to disable auth still works but is deprecated and will be rejected in the next major version. Omit the field instead.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/health&lt;/code&gt; never requires a token.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Note:&lt;/strong&gt; Only run without authentication on localhost or inside an isolated, private network.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Check Out the Project
&lt;/h2&gt;

&lt;p&gt;Cacheiro is a self-hosted, modular remote cache server for Nx and Lerna monorepos, with filesystem, S3, GCS and Azure Blob stores.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full documentation:&lt;/strong&gt; &lt;a href="https://rerodrigues.github.io/nx-remote-cache-server/" rel="noopener noreferrer"&gt;Cacheiro docs site&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security guide:&lt;/strong&gt; &lt;a href="https://rerodrigues.github.io/nx-remote-cache-server/guide/security" rel="noopener noreferrer"&gt;Read-only tokens, optional auth and HTTPS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source code:&lt;/strong&gt; &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have you put cache poisoning protections in place in your monorepo pipelines? Let's discuss in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devops</category>
      <category>security</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Creating your own Remote Cache Server for Nx and Lerna with Cacheiro</title>
      <dc:creator>Renato Rodrigues</dc:creator>
      <pubDate>Sun, 14 Jun 2026 01:40:35 +0000</pubDate>
      <link>https://dev.to/rerodrigues/creating-your-own-remote-cache-server-for-nx-and-lerna-with-cacheiro-2dcg</link>
      <guid>https://dev.to/rerodrigues/creating-your-own-remote-cache-server-for-nx-and-lerna-with-cacheiro-2dcg</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🌐 &lt;em&gt;Este artigo também está disponível em &lt;a href="https://dev.to/rerodrigues/criando-seu-proprio-servidor-de-cache-remoto-para-nx-e-lerna-com-o-cacheiro-48a8"&gt;Português&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you work with monorepos using &lt;strong&gt;Nx&lt;/strong&gt; or &lt;strong&gt;Lerna&lt;/strong&gt;, you already know that remote caching is practically a superpower. The ability to run a build, test, or lint in your CI pipeline (or on a colleague's machine) and share that result instantly with the rest of the team saves precious hours of pipeline and processing time.&lt;/p&gt;

&lt;p&gt;To get this benefit, the default and official solution is Nx Cloud. It is a fantastic service, but it can weigh on the budget of smaller teams or run into strict data security policies at companies that require strict &lt;em&gt;self-hosted&lt;/em&gt; solutions.&lt;/p&gt;

&lt;p&gt;If you have tried to bypass Nx Cloud costs recently, you most likely faced a chaotic scenario.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rollercoaster of Self-Hosted Caching in Nx
&lt;/h2&gt;

&lt;p&gt;The history of hosting your own cache in Nx feels like a soap opera. In the beginning, the community relied on third-party tools. Then, Nx (formerly NRWL) removed free open-source support, centralizing everything into their paid tier. Later, they backtracked and released official, free packages for self-hosting (featuring plugins for File System, AWS S3, Google Cloud Storage, and Azure).&lt;/p&gt;

&lt;p&gt;And then came the recent cold shower: &lt;strong&gt;Nx abruptly deprecated all official self-hosted cache packages due to security concerns&lt;/strong&gt; (you can check the details in the &lt;a href="https://nx.dev/docs/reference/deprecated/self-hosted-cache-packages" rel="noopener noreferrer"&gt;official Nx deprecation documentation&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The remote caching capability still natively exists within the Nx core, but the community was left stranded without official, secure tools to bridge the connection to storage providers. To deeply understand this rollercoaster, Emily Xiong's Medium article does an incredible job of detailing this &lt;a href="https://emilyxiong.medium.com/exploring-of-nx-self-hosted-cache-5bc39bd2ed7f" rel="noopener noreferrer"&gt;history of caching solutions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And it was precisely while dealing with this situation, as I was studying ways to optimize my CI, that I decided to build a solution to fill this gap.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Author's note: Despite the shifts in strategy, a huge shout-out goes to the Nx team for keeping the architecture open enough to allow the community to build alternative solutions.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introducing &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;&lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt;&lt;/strong&gt; project was born to give the community back the freedom to host their own remote cache securely, modernly, and completely for free.&lt;/p&gt;

&lt;p&gt;And before you ask: yes, the name is a play on words! It merges &lt;strong&gt;Cache&lt;/strong&gt; with the Portuguese suffix &lt;strong&gt;-eiro&lt;/strong&gt; (used to describe a profession, like a craftsman). "Cacheiro" is the one who takes care of your cache.&lt;/p&gt;

&lt;p&gt;Unlike other opinionated and rigid alternatives, &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt; was designed as a &lt;strong&gt;modular library&lt;/strong&gt;, published in individual packages. You pick and plug only what you actually need. It is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;100% Free and Open Source.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highly extensible:&lt;/strong&gt; you can easily customize the logic according to your infrastructure needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;100% Complete Ecosystem:&lt;/strong&gt; It ships with production-ready plugins for &lt;strong&gt;File System (FS)&lt;/strong&gt;, &lt;strong&gt;Amazon S3&lt;/strong&gt;, &lt;strong&gt;Azure Blob Storage&lt;/strong&gt;, and &lt;strong&gt;Google Cloud Storage (GCS)&lt;/strong&gt;, covering with full parity the gap left by the deprecated packages.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🔒 Security First:&lt;/strong&gt; Since the deprecation of the official Nx plugins happened due to security reasons, &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt; was built with double the attention to this aspect. The project strictly utilizes the latest versions of its underlying libraries (free of known vulnerabilities), underwent code auditing to mitigate common loopholes, and implements a robust encryption layer resilient against injection or artifact leaks.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  How to test it in less than 2 minutes (Practical Example)
&lt;/h2&gt;

&lt;p&gt;Even though &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt; is a library meant for building your custom server, the main repository already comes with a fully working example ready to run locally at &lt;code&gt;127.0.0.1:3000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want to see the magic happen right now on your machine using the File System (FS) plugin, just follow these quick steps:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Spin up the example server
&lt;/h3&gt;

&lt;p&gt;Clone the repository, install the dependencies at the root, configure the local runner environment, and start the development server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/rerodrigues/nx-remote-cache-server.git
&lt;span class="nb"&gt;cd &lt;/span&gt;nx-remote-cache-server
npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Navigate to the runner package and set up the environment&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;packages/cacheiro-runner
&lt;span class="nb"&gt;cp &lt;/span&gt;config/local.jsonc.example config/local.jsonc

&lt;span class="c"&gt;# Start the server&lt;/span&gt;
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;That's it! Your remote cache server is up and running at &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Connect your Nx or Lerna project
&lt;/h3&gt;

&lt;p&gt;Nx can identify and consume a remote cache directly via native environment variables. &lt;/p&gt;

&lt;p&gt;For a production or daily development setup, the ideal approach is to save these variables in your terminal configuration file (like &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt;) or inject them directly into your &lt;strong&gt;CI secrets / environment variables&lt;/strong&gt; (GitHub Actions, GitLab CI, etc.). &lt;/p&gt;

&lt;p&gt;For our local example, configure it using the default token (&lt;code&gt;change-me&lt;/code&gt;):&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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NX_REMOTE_CACHE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:3000"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NX_REMOTE_CACHE_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"change-me"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these variables defined in your monorepo's terminal, just run your project's standard commands:&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;# **If you are using Nx:**&lt;/span&gt;
npx nx run-many &lt;span class="nt"&gt;-t&lt;/span&gt; build

&lt;span class="c"&gt;# **If you are using Lerna:**&lt;/span&gt;
npx lerna run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the command once to generate and upload the cache to your local server. Run it a second time and witness the performance boost with the cache being served remotely by &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt;. Simple as that.&lt;/p&gt;




&lt;p&gt;If you are dealing with this infrastructure gap today, feel free to check out the project, drop a star, and contribute with feedback or Pull Requests!&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Access the GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;rerodrigues/nx-remote-cache-server&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;This is just the starting point. In the upcoming posts of this series, I will share practical, step-by-step guides on how to configure and use the plugins for each storage provider to get Cacheiro up and running in your cloud environment.&lt;/p&gt;




&lt;h3&gt;
  
  
  How about your team?
&lt;/h3&gt;

&lt;p&gt;How do you handle Nx caching today? Are you using Nx Cloud, did you migrate to another alternative, or were you stuck without knowing what to do after the official packages were deprecated?&lt;/p&gt;

&lt;p&gt;Leave a comment below, share your experience, and let's talk about it! See you in the next post!&lt;/p&gt;

</description>
      <category>nx</category>
      <category>lerna</category>
      <category>devops</category>
      <category>cache</category>
    </item>
    <item>
      <title>Criando seu próprio Servidor de Cache Remoto para Nx e Lerna com o Cacheiro</title>
      <dc:creator>Renato Rodrigues</dc:creator>
      <pubDate>Sun, 14 Jun 2026 01:32:13 +0000</pubDate>
      <link>https://dev.to/rerodrigues/criando-seu-proprio-servidor-de-cache-remoto-para-nx-e-lerna-com-o-cacheiro-48a8</link>
      <guid>https://dev.to/rerodrigues/criando-seu-proprio-servidor-de-cache-remoto-para-nx-e-lerna-com-o-cacheiro-48a8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🌐 &lt;em&gt;This article is also available in &lt;a href="https://dev.to/rerodrigues/creating-your-own-remote-cache-server-for-nx-and-lerna-with-cacheiro-2dcg"&gt;English&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se você trabalha com monorepos usando &lt;strong&gt;Nx&lt;/strong&gt; ou &lt;strong&gt;Lerna&lt;/strong&gt;, sabe que o cache remoto é praticamente um superpoder. A capacidade de rodar um build, teste ou lint no CI (ou na máquina de um colega) e compartilhar esse resultado instantaneamente com o resto do time economiza horas preciosas de pipeline e processamento.&lt;/p&gt;

&lt;p&gt;Para ter esse benefício, a solução padrão e oficial é o Nx Cloud. É um serviço fantástico, mas que pode pesar no orçamento de times menores ou esbarrar em políticas estritas de segurança de dados de algumas empresas que exigem soluções &lt;em&gt;self-hosted&lt;/em&gt; (auto-hospedadas).&lt;/p&gt;

&lt;p&gt;Se você tentou fugir dos custos do Nx Cloud recentemente, provavelmente se deparou com um cenário caótico.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Montanha-Russa do Cache Self-Hosted no Nx
&lt;/h2&gt;

&lt;p&gt;O histórico de quem tenta hospedar o próprio cache no Nx parece uma novela. No início, a comunidade dependia de ferramentas próprias. Depois, a Nx (antiga NRWL) removeu o suporte gratuito open-source, centralizando tudo no plano pago. Mais tarde, voltaram atrás e lançaram pacotes oficiais e gratuitos para self-hosting (com plugins para File System, AWS S3, Google Cloud Storage e Azure).&lt;/p&gt;

&lt;p&gt;E então veio o balde de água fria recente: &lt;strong&gt;a Nx descontinuou abruptamente todos os pacotes oficiais de self-hosted cache devido a problemas de segurança&lt;/strong&gt; (você pode conferir os detalhes na &lt;a href="https://nx.dev/docs/reference/deprecated/self-hosted-cache-packages" rel="noopener noreferrer"&gt;documentação oficial de depreciação do Nx&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;A funcionalidade de cache remoto ainda existe nativamente no core do Nx, mas a comunidade ficou órfã de ferramentas oficiais e seguras para fazer a ponte com os storages. Para entender a fundo essa novela, o artigo da Emily Xiong no Medium detalha incrivelmente bem esse &lt;a href="https://emilyxiong.medium.com/exploring-of-nx-self-hosted-cache-5bc39bd2ed7f" rel="noopener noreferrer"&gt;histórico das soluções de cache&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;E foi exatamente passando por essa situação enquanto estudava maneiras de otimizar meu CI que decidi criar uma solução para cobrir essa lacuna.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Nota de reconhecimento: Apesar das mudanças de diretrizes, fica aqui um agradecimento ao time da Nx por manter a arquitetura aberta o suficiente para permitir que a comunidade desenvolva soluções alternativas.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Apresentando o &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;O &lt;strong&gt;&lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt;&lt;/strong&gt; nasceu para devolver à comunidade a liberdade de hospedar seu próprio cache remoto de forma segura, moderna e totalmente gratuita.&lt;/p&gt;

&lt;p&gt;E antes que você pergunte: sim, o nome é uma brincadeira! É a junção de &lt;strong&gt;Cache&lt;/strong&gt; com o sufixo &lt;strong&gt;-eiro&lt;/strong&gt; (como em &lt;em&gt;pedreiro&lt;/em&gt; ou &lt;em&gt;carpinteiro&lt;/em&gt;). O "Cacheiro" é, literalmente, aquele que cuida do seu cache.&lt;/p&gt;

&lt;p&gt;Diferente de outras soluções engessadas (&lt;em&gt;opinionated&lt;/em&gt;), o &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt; foi desenhado como uma &lt;strong&gt;biblioteca modular&lt;/strong&gt;, disponibilizada em pacotes individuais. Você escolhe e acopla apenas o que precisa. Ele é:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;100% Livre e Open Source.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Altamente extensível:&lt;/strong&gt; você pode personalizar a lógica conforme a necessidade da sua infraestrutura.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecossistema 100% completo:&lt;/strong&gt; Já conta com plugins oficiais e prontos para &lt;strong&gt;Sistema de Arquivos (FS)&lt;/strong&gt;, &lt;strong&gt;Amazon S3&lt;/strong&gt;, &lt;strong&gt;Azure Blob Storage&lt;/strong&gt; e &lt;strong&gt;Google Cloud Storage (GCS)&lt;/strong&gt;, cobrindo com total paridade a lacuna deixada pelos pacotes descontinuados.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🔒 Segurança em Primeiro Lugar:&lt;/strong&gt; Como a descontinuação dos plugins da Nx aconteceu por motivos de segurança, o &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt; foi construído com atenção redobrada nesse aspecto. O projeto utiliza estritamente as versões mais recentes de suas bibliotecas base (sem vulnerabilidades conhecidas), passou por auditoria de código para mitigar brechas comuns e implementa uma camada de criptografia robusta e resiliente contra falhas de injeção ou vazamento de artefatos.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Como testar em menos de 2 minutos (Exemplo Prático)
&lt;/h2&gt;

&lt;p&gt;Embora o &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt; seja uma biblioteca para você construir o seu servidor customizado, o repositório principal já vem com um exemplo funcional pronto para rodar localmente no endereço &lt;code&gt;127.0.0.1:3000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Se você quer ver a mágica acontecer agora mesmo na sua máquina usando o plugin de File System (FS), basta seguir estes passos rápidos:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Suba o servidor de exemplo
&lt;/h3&gt;

&lt;p&gt;Clone o repositório, instale as dependências na raiz, configure o arquivo local do runner e inicie o servidor de desenvolvimento:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/rerodrigues/nx-remote-cache-server.git
&lt;span class="nb"&gt;cd &lt;/span&gt;nx-remote-cache-server
npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Navegue até o pacote do runner e configure o ambiente&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;packages/cacheiro-runner
&lt;span class="nb"&gt;cp &lt;/span&gt;config/local.jsonc.example config/local.jsonc

&lt;span class="c"&gt;# Inicie o servidor&lt;/span&gt;
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pronto! Seu servidor de cache remoto está rodando no endereço &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Conecte o seu projeto Nx ou Lerna
&lt;/h3&gt;

&lt;p&gt;O Nx consegue identificar e usar o cache remoto diretamente através de variáveis de ambiente nativas. &lt;/p&gt;

&lt;p&gt;Para o ambiente de produção ou desenvolvimento diário, o ideal é salvar essas variáveis no arquivo de configuração do seu terminal (como &lt;code&gt;.bashrc&lt;/code&gt; ou &lt;code&gt;.zshrc&lt;/code&gt;) ou configurá-las diretamente nos &lt;strong&gt;Secrets / Environment Variables do seu CI&lt;/strong&gt; (GitHub Actions, GitLab CI, etc.). &lt;/p&gt;

&lt;p&gt;Para o nosso exemplo local, configure com o token padrão (&lt;code&gt;change-me&lt;/code&gt;):&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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NX_REMOTE_CACHE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:3000"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NX_REMOTE_CACHE_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"change-me"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com as variáveis definidas no terminal do seu monorepositório, basta rodar os comandos padrão do seu projeto:&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;# **Se você usa Nx:**&lt;/span&gt;
npx nx run-many &lt;span class="nt"&gt;-t&lt;/span&gt; build

&lt;span class="c"&gt;# **Se você usa Lerna:**&lt;/span&gt;
npx lerna run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute o comando uma vez para gerar e enviar o cache para o servidor local. Rode uma segunda vez e veja o ganho de performance com o cache sendo servido remotamente pelo &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;Cacheiro&lt;/a&gt;. Simples assim.&lt;/p&gt;




&lt;p&gt;Se você está enfrentando esse desafio hoje, convido você a conhecer o projeto, deixar sua estrela e contribuir com feedbacks ou Pull Requests!&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Acesse o repositório no GitHub:&lt;/strong&gt; &lt;a href="https://github.com/rerodrigues/nx-remote-cache-server" rel="noopener noreferrer"&gt;rerodrigues/nx-remote-cache-server&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  O que vem a seguir?
&lt;/h2&gt;

&lt;p&gt;Este é apenas o ponto de partida. Nos próximos posts desta série, trarei tutoriais práticos demonstrando detalhadamente como configurar e usar os plugins de cada storage para colocar o Cacheiro em produção no seu ambiente de nuvem.&lt;/p&gt;




&lt;h3&gt;
  
  
  E no seu time?
&lt;/h3&gt;

&lt;p&gt;Como vocês lidam com o cache do Nx hoje? Usam o Nx Cloud, migraram para outra alternativa ou estavam travados sem saber o que fazer após a descontinuação dos pacotes oficiais? &lt;/p&gt;

&lt;p&gt;Deixe seu comentário abaixo, conte sua experiência e vamos trocar uma ideia! Nos vemos no próximo post!&lt;/p&gt;

</description>
      <category>ptbr</category>
      <category>nx</category>
      <category>lerna</category>
      <category>devops</category>
    </item>
    <item>
      <title>Typescript scripts in the command line: The Conclusion</title>
      <dc:creator>Renato Rodrigues</dc:creator>
      <pubDate>Mon, 24 Feb 2025 23:21:09 +0000</pubDate>
      <link>https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-the-conclusion-56ma</link>
      <guid>https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-the-conclusion-56ma</guid>
      <description>&lt;h2&gt;
  
  
  Conclusion and Final thoughts
&lt;/h2&gt;

&lt;p&gt;In the previous articles in this series, we introduced an example &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-deno-20-vs-nodejs-3o3b"&gt;&lt;strong&gt;Typescript&lt;/strong&gt; script&lt;/a&gt; and implemented it in &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-deno-20-l22"&gt;&lt;strong&gt;Deno 2.0&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-nodejs-9ad"&gt;&lt;strong&gt;Node.JS&lt;/strong&gt;&lt;/a&gt;. The idea was to show how to achieve the same results using the two different technologies, enumerate the pros and cons of each implementation, and hopefully help you decide which one suits you better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adoption
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Node.JS&lt;/strong&gt; is the industry standard and has been around for over 15 years. &lt;strong&gt;Deno&lt;/strong&gt;, on the other hand, is a more recent technology, especially the version &lt;em&gt;2.0&lt;/em&gt;. Using &lt;strong&gt;Deno&lt;/strong&gt; in a more critical, conservative, or controlled environment could be difficult or even not allowed at all. In those cases, &lt;strong&gt;Node.JS&lt;/strong&gt; could be a more suitable choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deno 2.0 Implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Pros
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;No setup required&lt;/li&gt;
&lt;li&gt;Native &lt;em&gt;Typescript&lt;/em&gt; support&lt;/li&gt;
&lt;li&gt;No transpilation required&lt;/li&gt;
&lt;li&gt;Native support for &lt;em&gt;NPM&lt;/em&gt; dependencies&lt;/li&gt;
&lt;li&gt;Single-file script&lt;/li&gt;
&lt;li&gt;No project file, lock file, or node_modules folder&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cons
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Not widely available in existing &lt;em&gt;Docker&lt;/em&gt; images and containers&lt;/li&gt;
&lt;li&gt;Minimal, yet existing, learning curve&lt;/li&gt;
&lt;li&gt;May face resistance or opposition to the adoption&lt;/li&gt;
&lt;li&gt;May not be approved and allowed in highly controlled corporate environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Node.JS Implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Pros
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Familiar to developers and sys-admins, no learning curve&lt;/li&gt;
&lt;li&gt;Widely available in the most commonly used images and containers&lt;/li&gt;
&lt;li&gt;Approved for use in most environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cons
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Doesn't run &lt;em&gt;Typescript&lt;/em&gt; natively&lt;/li&gt;
&lt;li&gt;Transpilation will be needed&lt;/li&gt;
&lt;li&gt;Requires a project file, a lock file, and a node_modules &lt;/li&gt;
&lt;li&gt;Your script is actually a multi-file project, not a single-file script&lt;/li&gt;
&lt;li&gt;Has problems mixing &lt;a href="https://nodejs.org/api/modules.html#modules-commonjs-modules" rel="noopener noreferrer"&gt;&lt;em&gt;CommonJS&lt;/em&gt;&lt;/a&gt; and &lt;a href="https://nodejs.org/api/esm.html#modules-ecmascript-modules" rel="noopener noreferrer"&gt;&lt;em&gt;ESM&lt;/em&gt;&lt;/a&gt; modules&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The verdict
&lt;/h2&gt;

&lt;p&gt;The Pros and Cons above can be of great help when choosing which technology to use. While I cannot assert which one is better for your scenario, I can say that in an environment where none of the cons are a concern, I personally would choose &lt;strong&gt;Deno 2.0&lt;/strong&gt; and advise you to do the same. However, if one of the cons is a no-go for you, it's better to stay safe in the &lt;strong&gt;Node.JS&lt;/strong&gt; ship.&lt;/p&gt;

&lt;p&gt;This concludes this series of articles on &lt;strong&gt;Typescript scripts&lt;/strong&gt; on the Command Line. I hope you enjoyed it.&lt;/p&gt;

&lt;p&gt;Stay tuned for more content like this.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>deno</category>
      <category>node</category>
      <category>cli</category>
    </item>
    <item>
      <title>Typescript scripts in the command line: Using Node.JS</title>
      <dc:creator>Renato Rodrigues</dc:creator>
      <pubDate>Thu, 06 Feb 2025 23:06:54 +0000</pubDate>
      <link>https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-nodejs-9ad</link>
      <guid>https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-nodejs-9ad</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-deno-20-l22"&gt;previous article&lt;/a&gt; in this series, we saw how to implement an example &lt;em&gt;Typescript&lt;/em&gt; &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-deno-20-l22"&gt;script in &lt;strong&gt;Deno 2.0&lt;/strong&gt;&lt;/a&gt; and run it from the command line. In this article, for the sake of comparison, we will see how to achieve the same using &lt;strong&gt;Node.JS&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Node.JS and Typescript support
&lt;/h2&gt;

&lt;p&gt;Before starting, let's demystify one thing. &lt;strong&gt;Node.JS&lt;/strong&gt;, at the time of writing, &lt;strong&gt;DOES NOT&lt;/strong&gt; support &lt;em&gt;Typescript&lt;/em&gt;. You may have seen some headlines recently stating that, but actually, what &lt;em&gt;Node&lt;/em&gt; has is something called &lt;strong&gt;Typescript type stripping&lt;/strong&gt;, which, as the name implies, just strips the &lt;strong&gt;Typescript&lt;/strong&gt; portion of the code and interprets the remaining as regular &lt;strong&gt;Javascript&lt;/strong&gt; code, ignoring any &lt;em&gt;TS&lt;/em&gt; feature on it.&lt;/p&gt;

&lt;p&gt;Type stripping was implemented first as an experimental flag on &lt;em&gt;Node 22&lt;/em&gt; and will be enabled by default on &lt;em&gt;Node 23&lt;/em&gt;. It is also currently not complete and lacks support for some &lt;em&gt;Typescript&lt;/em&gt; features, like &lt;code&gt;ENUMS&lt;/code&gt; and &lt;code&gt;Namespaces&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For these reasons, I like to think that &lt;strong&gt;Node.JS&lt;/strong&gt;, in its current state, more likely tolerates (and ignores) &lt;em&gt;Typescript&lt;/em&gt; than actually supports it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the Script Using Node.JS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initializing the project
&lt;/h3&gt;

&lt;p&gt;First of all, we need to create a new folder and then initialize a &lt;strong&gt;Node.JS&lt;/strong&gt; project there. For this, type in a &lt;em&gt;Terminal&lt;/em&gt; window&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="nb"&gt;mkdir &lt;/span&gt;sayHello
&lt;span class="nb"&gt;cd &lt;/span&gt;sayHello
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Installing the external dependencies
&lt;/h4&gt;

&lt;p&gt;To use external dependencies (&lt;em&gt;NPM modules&lt;/em&gt;) in &lt;strong&gt;Node.JS&lt;/strong&gt;, we must first install them and then add them to our script.&lt;/p&gt;

&lt;p&gt;Install &lt;a href="https://www.npmjs.com/package/chalk" rel="noopener noreferrer"&gt;chalk&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/yosay" rel="noopener noreferrer"&gt;yosay&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/inquirer" rel="noopener noreferrer"&gt;inquirer&lt;/a&gt; and its types from &lt;strong&gt;NPM&lt;/strong&gt; by typing in the Terminal window&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;chalk yosay inquirer
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @types/yosay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating the script
&lt;/h3&gt;

&lt;p&gt;Inside the &lt;code&gt;sayHello&lt;/code&gt; folder, create a new folder called &lt;code&gt;src&lt;/code&gt;, and inside it, a file called &lt;code&gt;sayHello.ts&lt;/code&gt;.&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="nb"&gt;mkdir &lt;/span&gt;src
&lt;span class="nb"&gt;touch &lt;/span&gt;src/sayHello.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Importing the external dependencies
&lt;/h4&gt;

&lt;p&gt;Import the dependencies to the script by opening &lt;code&gt;src/sayHello.ts&lt;/code&gt; in your editor and add the following lines&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="c1"&gt;// src/sayHello.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;chalk&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;chalk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;yosay&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;yosay&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;inquirer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Answers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inquirer&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;h4&gt;
  
  
  Implementing the script body
&lt;/h4&gt;

&lt;p&gt;With the dependencies added, it's time to implement the script body. For this, add the following lines to &lt;code&gt;src/sayHello.ts&lt;/code&gt; after the &lt;em&gt;import&lt;/em&gt; block&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="c1"&gt;// src/sayHello.ts&lt;/span&gt;
&lt;span class="c1"&gt;// import ...&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;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;Hello visitor, please enter you details:&lt;/span&gt;&lt;span class="se"&gt;\n&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;questions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Answers&lt;/span&gt; &lt;span class="o"&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What's your name?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;salutation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;How should I refer to you?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;choices&lt;/span&gt;&lt;span class="p"&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;Mr.&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;Mrs.&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;none&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="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;inquirer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;questions&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;answers&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;salutation&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;answers&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="s2"&gt;`\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[SUCCESS]:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; information entered was correct`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;person&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="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;salutation&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;salutation&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;yosay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hallo &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="s2"&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;Save the changes, and next, we will run the script.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the script from source
&lt;/h3&gt;

&lt;p&gt;OK, now we have the script ready, but how do we run it? That's where things get a bit more complicated. In &lt;strong&gt;Node.JS&lt;/strong&gt;, the short answer is that we cannot run it directly. You need to &lt;em&gt;transpile&lt;/em&gt; it before running or use a dedicated tool to do it transparently for us. &lt;em&gt;(again, ignore Node's type stripping feature)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So how do we run it then?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First of all, install the &lt;strong&gt;TSX&lt;/strong&gt; dependency. In the terminal window, do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we have three ways of running the script &lt;strong&gt;from source&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method 1:&lt;/strong&gt; Using &lt;strong&gt;NPX&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the &lt;code&gt;sayHello&lt;/code&gt; folder, do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsx src/sayHello.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will use a tool called &lt;strong&gt;TSX&lt;/strong&gt; to transpile and run the &lt;em&gt;TS&lt;/em&gt; code transparently&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method 2:&lt;/strong&gt; Adding an alias to &lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;package.json&lt;/code&gt; file in your editor and add this line into the &lt;strong&gt;scripts&lt;/strong&gt; section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;existing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;script&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsx src/sayHello.ts"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then, on &lt;code&gt;sayHello&lt;/code&gt; folder, just do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm start

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Method 3:&lt;/strong&gt; Making the script executable &lt;em&gt;(Linux/MacOS)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Add this line &lt;strong&gt;at the top&lt;/strong&gt; of &lt;code&gt;src/sayHello.ts&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="cp"&gt;#!/usr/bin/env -S npx tsx
&lt;/span&gt;
&lt;span class="c1"&gt;// src/sayHello.ts&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;open a Terminal window and run&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="nb"&gt;chmod&lt;/span&gt; +x src/sayHello.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then, every time you need to run the script, in the &lt;code&gt;sayHello&lt;/code&gt; folder, do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./src/sayHello.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the script using the desired method, answer the questions, and check the output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Going Further
&lt;/h3&gt;

&lt;p&gt;Following the above steps, we were able to implement and run the same script we had in &lt;strong&gt;Deno 2.0&lt;/strong&gt;. But there is one major difference. While Deno is truly running the script as-is, &lt;strong&gt;Node.JS&lt;/strong&gt;, runs a transformed version of it that &lt;em&gt;TSX&lt;/em&gt; generates. Let's say we have two versions of the script, the one we developed (in &lt;em&gt;TS&lt;/em&gt;) and the other that &lt;em&gt;Node&lt;/em&gt; runs natively (converted from &lt;em&gt;TS&lt;/em&gt; to &lt;em&gt;JS&lt;/em&gt; by &lt;em&gt;TSX&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;What are the implications? For big and complex projects, it could make things slower and require more resources, but for a small command line script, I would say none, if any at all.&lt;/p&gt;

&lt;p&gt;What if I want to run the &lt;em&gt;"translated"&lt;/em&gt; version of the script in Node and run it natively? Is it possible? Yes, it is, and this process we call &lt;em&gt;transpilation&lt;/em&gt;, it's a bit complex topic and out of the scope of this article, so we are not covering it now. We may have it covered in an appendix after finishing this series. Stay tuned for more information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;That's it. That's all we need to know to run a &lt;strong&gt;Typescript&lt;/strong&gt; script with external dependencies, on the command line, using &lt;strong&gt;Node.JS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can check &lt;a href="https://github.com/rerodrigues/node-say-hello" rel="noopener noreferrer"&gt;the complete source code&lt;/a&gt; of the &lt;strong&gt;Node.JS&lt;/strong&gt; version of the script &lt;a href="https://github.com/rerodrigues/node-say-hello" rel="noopener noreferrer"&gt;here&lt;/a&gt; as well the source code of the &lt;a href="https://github.com/rerodrigues/deno-say-hello" rel="noopener noreferrer"&gt;Deno 2.0 version&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-the-conclusion-56ma"&gt;next article&lt;/a&gt; in this series, we will summarize both implementations and &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-the-conclusion-56ma"&gt;wrap up&lt;/a&gt; our findings with thoughtful conclusions.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>deno</category>
      <category>node</category>
      <category>cli</category>
    </item>
    <item>
      <title>Typescript scripts in the command line: Using Deno 2.0</title>
      <dc:creator>Renato Rodrigues</dc:creator>
      <pubDate>Sun, 19 Jan 2025 20:25:27 +0000</pubDate>
      <link>https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-deno-20-l22</link>
      <guid>https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-deno-20-l22</guid>
      <description>&lt;p&gt;This article is part of a series comparing &lt;strong&gt;Deno 2.0&lt;/strong&gt; and &lt;strong&gt;Node.JS&lt;/strong&gt;'s capabilities for running Typescript scripts with external dependencies from the command line. For a broader overview, refer to the &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-deno-20-vs-nodejs-3o3b"&gt;first page&lt;/a&gt; of the series. This is the &lt;strong&gt;Deno 2.0&lt;/strong&gt; implementation; stay tuned for the &lt;strong&gt;Node.JS&lt;/strong&gt; implementation of the same script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the Script Using Deno 2.0
&lt;/h2&gt;

&lt;p&gt;Since the beginning, &lt;strong&gt;Deno&lt;/strong&gt; was able to run &lt;strong&gt;Typescript&lt;/strong&gt; scripts natively, without the need for transpilation or any extra step. What was changed in &lt;strong&gt;Deno 2.0&lt;/strong&gt; was the ability to import and run &lt;strong&gt;NPM&lt;/strong&gt; dependencies in your script without needing initialization steps, a project file, transpilation, or bundle steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment setup
&lt;/h3&gt;

&lt;p&gt;Before starting, make sure you have &lt;strong&gt;Deno&lt;/strong&gt;, at least at version &lt;strong&gt;2.0&lt;/strong&gt; installed on your machine. For that, in a terminal window, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deno &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get an error, or a version older than &lt;strong&gt;2.0&lt;/strong&gt;, check &lt;a href="https://docs.deno.com/runtime/#install-deno" rel="noopener noreferrer"&gt;this page&lt;/a&gt; for instructions on how to install/update &lt;strong&gt;Deno&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  VS Code
&lt;/h4&gt;

&lt;p&gt;If you are using &lt;strong&gt;VS Code&lt;/strong&gt;, which I recommend, you may want to install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno" rel="noopener noreferrer"&gt;official VS Code Deno extension&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the script
&lt;/h3&gt;

&lt;p&gt;In a folder of your choice create a file called &lt;code&gt;sayHello.ts&lt;/code&gt; and open it in your editor.&lt;/p&gt;

&lt;h4&gt;
  
  
  Importing external dependencies
&lt;/h4&gt;

&lt;p&gt;To use external dependencies, such as &lt;strong&gt;NPM&lt;/strong&gt; modules, in &lt;strong&gt;Deno&lt;/strong&gt;, all you need to do is import it in your script file, following the syntax &lt;code&gt;registry_type:package_name@package_version&lt;/code&gt; as illustrated below.&lt;/p&gt;

&lt;p&gt;Add &lt;a href="https://www.npmjs.com/package/chalk" rel="noopener noreferrer"&gt;chalk&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/yosay" rel="noopener noreferrer"&gt;yosay&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/inquirer" rel="noopener noreferrer"&gt;inquirer&lt;/a&gt; from &lt;strong&gt;NPM&lt;/strong&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="c1"&gt;// sayHello.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;chalk&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;npm:chalk@5.3.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;yosay&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;npm:yosay@3.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;inquirer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Answers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npm:inquirer@12.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;If you are using VS Code, hover over the red error lines, click on &lt;strong&gt;Quick fix&lt;/strong&gt;, and choose &lt;strong&gt;Cache all dependencies of this module&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementing the script body
&lt;/h4&gt;

&lt;p&gt;Add the following lines to &lt;code&gt;sayHello.ts&lt;/code&gt; after the &lt;em&gt;import&lt;/em&gt; block&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="c1"&gt;// sayHello.ts&lt;/span&gt;
&lt;span class="c1"&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;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;Hello visitor, please enter you details:&lt;/span&gt;&lt;span class="se"&gt;\n&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;questions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Answers&lt;/span&gt; &lt;span class="o"&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What's your name?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;salutation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;How should I refer to you?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;choices&lt;/span&gt;&lt;span class="p"&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;Mr.&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;Mrs.&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;none&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="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;inquirer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;questions&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;answers&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;salutation&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;answers&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="s2"&gt;`\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[SUCCESS]:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; information entered was correct`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;person&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="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;salutation&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;salutation&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;yosay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hallo &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="s2"&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;h4&gt;
  
  
  Running the script
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Method 1:&lt;/strong&gt; Using &lt;code&gt;deno&lt;/code&gt; command&lt;/p&gt;

&lt;p&gt;Open a terminal window and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deno &lt;span class="nt"&gt;-A&lt;/span&gt; sayHello.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The -A option gives &lt;strong&gt;Deno&lt;/strong&gt; all the permissions needed to download the external dependencies and run the code locally.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method 2:&lt;/strong&gt; Making the script executable &lt;em&gt;(Linux/MacOS)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Add this line &lt;strong&gt;at the top&lt;/strong&gt; of &lt;code&gt;sayHello.ts&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="cp"&gt;#!/usr/bin/env -S deno -A
&lt;/span&gt;
&lt;span class="c1"&gt;// sayHello.ts&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;open a terminal window and run&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="nb"&gt;chmod&lt;/span&gt; +x sayHello.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then, every time you need to run the script, in the script folder, do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./sayHello.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run your script using the desired method, answer the questions, and check the output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;That's it. That's all you need to do to run a &lt;strong&gt;Typescript&lt;/strong&gt; script with external dependencies on the command line using &lt;strong&gt;Deno 2.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can check &lt;a href="https://github.com/rerodrigues/deno-say-hello" rel="noopener noreferrer"&gt;the complete source code&lt;/a&gt; of the &lt;strong&gt;Deno&lt;/strong&gt; version of the script &lt;a href="https://github.com/rerodrigues/deno-say-hello" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-nodejs-9ad"&gt;next article&lt;/a&gt; in this series, we will explore how to achieve the same functionality &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-nodejs-9ad"&gt;using &lt;strong&gt;Node.JS&lt;/strong&gt;&lt;/a&gt; instead of &lt;em&gt;Deno&lt;/em&gt;. Check it out!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(and yes, I know that Node &amp;gt;= 22 has primitive support for TypeScript, but it's so primitive that I'd say it tolerates (and ignores) TS more than it actually supports it. More on that in the next article)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>deno</category>
      <category>node</category>
      <category>cli</category>
    </item>
    <item>
      <title>Typescript scripts in the command line: Deno 2.0 vs Node.JS</title>
      <dc:creator>Renato Rodrigues</dc:creator>
      <pubDate>Sun, 19 Jan 2025 20:24:40 +0000</pubDate>
      <link>https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-deno-20-vs-nodejs-3o3b</link>
      <guid>https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-deno-20-vs-nodejs-3o3b</guid>
      <description>&lt;p&gt;Whether you are new to the development world or a seasoned developer, scripts make life easier. They automate repetitive tasks, streamline complex processes, and produce predictable output, phasing out the human factor that could lead to errors. Everyone loves a well-written script.&lt;/p&gt;

&lt;p&gt;Historically, scripts have been written mostly in &lt;em&gt;Shell Script&lt;/em&gt;, &lt;em&gt;Python&lt;/em&gt;, or &lt;em&gt;Ruby&lt;/em&gt; languages. In recent years, however, &lt;em&gt;Javascript&lt;/em&gt; started making its way into this universe. A good reason to use &lt;em&gt;Javascript&lt;/em&gt; for this is the familiarity that most developers have with this language. However, a reason not to use it is that &lt;em&gt;Javascript&lt;/em&gt;, in its purest form, is limited and inferior to the aforementioned languages, and it´s not easy to extend its functionality using external dependencies. &lt;em&gt;Typescript&lt;/em&gt; can be seen as an evolution to &lt;em&gt;Javascript&lt;/em&gt;, and it is even more complicated to create a &lt;em&gt;Typescript&lt;/em&gt; script and run it from the command line.&lt;/p&gt;

&lt;p&gt;This scenario changed forever with the release of &lt;strong&gt;Deno 2.0&lt;/strong&gt; which makes running &lt;strong&gt;Javascript&lt;/strong&gt; AND &lt;strong&gt;Typescript&lt;/strong&gt; scripts natively, with support for external dependencies, a breeze.&lt;/p&gt;

&lt;p&gt;In this series of articles, we will explore the possibilities of creating &lt;strong&gt;Typescript&lt;/strong&gt; scripts that use external libraries, such as those from &lt;em&gt;Node's NPM&lt;/em&gt; or &lt;em&gt;Deno's JSR&lt;/em&gt;, and running them using &lt;strong&gt;Deno 2&lt;/strong&gt;. Then, for the sake of comparison, we will see how to achieve the same using &lt;strong&gt;Node.JS&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The sample script
&lt;/h3&gt;

&lt;p&gt;The sample script is a simple command line interface &lt;em&gt;(CLI)&lt;/em&gt; script that asks you some questions and then prints them formatted to the terminal, based on your input. Its purpose is to show you how to run a &lt;em&gt;Typescript&lt;/em&gt; script that uses external dependencies from the command line.&lt;/p&gt;

&lt;p&gt;Head to the &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-deno-20-l22"&gt;next page&lt;/a&gt; to see how to &lt;a href="https://dev.to/rerodrigues/typescript-scripts-in-the-command-line-using-deno-20-l22"&gt;implement it using Deno 2.0&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>deno</category>
      <category>node</category>
      <category>cli</category>
    </item>
    <item>
      <title>Programação Funcional em JS, Imutabilidade e Reducers com Immer</title>
      <dc:creator>Renato Rodrigues</dc:creator>
      <pubDate>Thu, 11 Nov 2021 13:06:56 +0000</pubDate>
      <link>https://dev.to/rerodrigues/programacao-funcional-em-js-imutabilidade-e-reducers-com-immer-gj2</link>
      <guid>https://dev.to/rerodrigues/programacao-funcional-em-js-imutabilidade-e-reducers-com-immer-gj2</guid>
      <description>&lt;h2&gt;
  
  
  Programação Funcional
&lt;/h2&gt;

&lt;p&gt;Resumidamente podemos dizer que as linguagens que trabalham com o paradigma de programação funcional seguem alguns preceitos básicos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Funções puras:&lt;/strong&gt;
Recebem as informações que precisam por parâmetros e retornam sempre o mesmo resultado se chamadas com os mesmos parâmetros;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sem efeitos colaterais:&lt;/strong&gt;
As funções não mutam informações fora de seus escopos;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stateless:&lt;/strong&gt;
As funções não possuem e não dependem de estados internos ou externos;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotentes:&lt;/strong&gt;
As funções podem ser chamadas um número infinito de vezes e em diferentes contexto que resultado vai ser sempre o mesmo se os argumentos forem os mesmos, não gerando side-effects nem persistindo nenhuma alteração.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Programação Funcional em Javascript
&lt;/h2&gt;

&lt;p&gt;Javascript por padrão não é uma linguagem funcional, porém por ser uma linguagem altamente flexível, adaptável e independente de paradigmas, os padrões de Programação Funcional podem ser utilizados em JS. É importante observar no entanto, que por ser uma linguagem extremamente permissiva e não te obrigar a praticamente nada, o Javascript não vai garantir que seu código siga todos os preceitos da PF. Fica a cargo do desenvolvedor aplicar esses preceitos corretamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Função não pura e com side effect em JS&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;externalCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;plus1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;externalCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;externalCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;externalCount&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;External count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;externalCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// External count: 0&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;internalCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;plus1&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;Internal count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;internalCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Internal count: 1&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;External count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;externalCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// External count: 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Programação Funcional em JS antes do ES5
&lt;/h3&gt;

&lt;p&gt;Antes do &lt;em&gt;ES5&lt;/em&gt; (&lt;a href="https://www.w3schools.com/js/js_es5.asp" rel="noopener noreferrer"&gt;ECMAScript 5th Edition&lt;/a&gt;) os conceitos de Programação Funcional praticamente não existiam em JS e só poderiam ser obtidos replicando manualmente esses comportamentos em seu código ou utilizando libs externas que faziam exatamente isso (ex, &lt;em&gt;&lt;a href="https://underscorejs.org/" rel="noopener noreferrer"&gt;Underscore.js&lt;/a&gt;&lt;/em&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Programação Funcional em JS com ES5 (~ 2012*)
&lt;/h3&gt;

&lt;p&gt;O &lt;em&gt;ES5&lt;/em&gt; trouxe para o mundo do JS alguns conceitos e funcionalidades de Programação Funcional, como por exemplo as funções &lt;em&gt;map&lt;/em&gt;, &lt;em&gt;filter&lt;/em&gt; e &lt;em&gt;reduce&lt;/em&gt;, possibilitando aplicar esse novo paradigma onde antes não era possível. As revisões futuras do ES vieram a reforçar esse suporte.&lt;/p&gt;

&lt;p&gt;* &lt;em&gt;O ES5 foi oficialmente criado em 2009, mas só começou mesmo a ser utilizado por volta de 2012 devido à incompatibilidade com a base instalada de navegadores antigos.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filtrando antes do ES5&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;evenNumbers&lt;/span&gt; &lt;span class="o"&gt;=&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;evenNumbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;// evenNumbers = 0, 2, 4, 6, 8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Filtrando com o ES5&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;evenNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// evenNumbers = 0, 2, 4, 6, 8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Imutabilidade
&lt;/h2&gt;

&lt;p&gt;Imutabilidade em seu conceito mais básico diz que uma informação após ser definida não pode ser mais alterada.&lt;br&gt;
Em programação isso traz algumas vantagens, como por exemplo garantir a consistência da informação durante todo o fluxo de dados, não gerar efeitos colaterais em funções, poder fazer referências à informação original ao invés de copiá-la, poder usar essa informação como índice ou chave, passá-la pra múltiplos threads e funções assíncronas, etc.&lt;/p&gt;
&lt;h2&gt;
  
  
  Imutabilidade em JS
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Valor x referência
&lt;/h3&gt;

&lt;p&gt;Em Javascript a maioria dos parâmetros são passados &lt;strong&gt;por referência&lt;/strong&gt;, ou seja, ao invés de serem copiados, uma referência à informações original será criada. Isso significa que qualquer alteração feita nesse parâmetro refletirá também na informação original em si e vice-versa.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tipos primitivos
&lt;/h3&gt;

&lt;p&gt;A exceção à essa regra são os &lt;strong&gt;tipos primitivos&lt;/strong&gt; da linguagem Javascript, que sempre são passados como &lt;strong&gt;valor&lt;/strong&gt;, sem nenhuma referência à informação original. São eles:&lt;br&gt;
&lt;code&gt;Boolean&lt;/code&gt;, &lt;code&gt;Number&lt;/code&gt;, &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Null&lt;/code&gt;, &lt;code&gt;Undefined&lt;/code&gt; e &lt;code&gt;Symbol&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tipos Object
&lt;/h3&gt;

&lt;p&gt;Tudo que não for um tipo primitivo em JS é do tipo &lt;code&gt;Object&lt;/code&gt; e esse tipo sempre é passado por referência, portanto &lt;strong&gt;NÃO&lt;/strong&gt; é imutável.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tipos primitivos não mutam&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;externalCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;plus1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;count&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;External count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;externalCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// External count: 0&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;internalCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;plus1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;externalCount&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;Internal count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;internalCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Internal count: 1&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;External count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;externalCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// External count: 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Já os tipos não primitivos (Object) mutam&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;externalCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;plus1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&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="nx"&gt;count&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;1&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;count&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;External count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;externalCount&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;// External count: 0&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;internalCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;plus1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;externalCount&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;Internal count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;internalCount&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;// Internal count: 1&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;External count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;externalCount&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;// External count: 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Então como obter imutabilidade em JS?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Pré ES5
&lt;/h4&gt;

&lt;p&gt;Até o advento do &lt;em&gt;ES5&lt;/em&gt; era praticamente inexistente o conceito de imutabilidade em JS, pelo menos de forma nativa, tendo que recorrer a libs externas que de alguma maneira tentavam emular esse comportamento.&lt;/p&gt;

&lt;h3&gt;
  
  
  ES5
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Object.assign
&lt;/h4&gt;

&lt;p&gt;O &lt;em&gt;ES5&lt;/em&gt; introduziu o método &lt;code&gt;assign&lt;/code&gt; aos objetos JS, que permite copiar o conteúdo de um número &lt;em&gt;N&lt;/em&gt; de objetos à direita ao objeto mais à esquerda, mutando o mesmo e retornando o resultado. Note que somente o objeto mais à esquerda é mutado, os demais não.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Object.assign mutando o objeto mais à esquerda&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&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;var&lt;/span&gt; &lt;span class="nx"&gt;lastNameOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&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;var&lt;/span&gt; &lt;span class="nx"&gt;emailOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&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;var&lt;/span&gt; &lt;span class="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastNameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emailOnly&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// nameOnly = { name: 'Renato', lastName: 'Rodrigues', email: 'renato.rodrigues@renatorodrigues.com' }&lt;/span&gt;
&lt;span class="c1"&gt;// myInfo = { name: 'Renato', lastName: 'Rodrigues', email: 'renato.rodrigues@renatorodrigues.com' }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Tá, mas e a imutabilidade?&lt;/em&gt; Lembrando que quando falamos de JS, a linguagem nos permite fazer praticamente qualquer coisa, temos então um pulo do gato aí. Em nenhum lugar é dito que o objeto mais à esquerda precisa ser uma referência a um objeto previamente criado. Ele pode ser simplesmente um objeto vazio, recém criado, que vai receber todos os valores à direita. Logo, se não existe uma referência pra ele, não existe o que mutar. ¯\&lt;em&gt;(ツ)&lt;/em&gt;/¯&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Object.assign NÃO mutando o objeto mais à esquerda&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastNameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emailOnly&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// nameOnly = { name: 'Renato' }&lt;/span&gt;
&lt;span class="c1"&gt;// myInfo = { name: 'Renato', lastName: 'Rodrigues', email: 'renato.rodrigues@renatorodrigues.com' }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Importante:&lt;/strong&gt;  O &lt;code&gt;Object.assign&lt;/code&gt; somente copia as propriedades de primeiro nível dos objetos em si, caso uma propriedade seja um objeto &lt;em&gt;nested&lt;/em&gt; ou faça uma referência a um objeto externo elas &lt;strong&gt;poderão&lt;/strong&gt; ser mutadas, pois continuarão a apontar para o objeto original.&lt;/p&gt;

&lt;h3&gt;
  
  
  ES6 (2015)
&lt;/h3&gt;

&lt;p&gt;O &lt;em&gt;ES6&lt;/em&gt; (&lt;a href="https://www.w3schools.com/js/js_es6.asp" rel="noopener noreferrer"&gt;ECMAScript 6th Edition&lt;/a&gt;, &lt;em&gt;a.k.a ES2015&lt;/em&gt;) trouxe mais algumas funções e funcionalidades relacionadas à imutabilidade, apesar de &lt;em&gt;*spoiler*&lt;/em&gt; nenhuma delas garantir uma imutabilidade 100%.&lt;/p&gt;

&lt;h4&gt;
  
  
  Const
&lt;/h4&gt;

&lt;p&gt;O &lt;em&gt;ES6&lt;/em&gt; trouxe ao JS o conceito de &lt;code&gt;constantes&lt;/code&gt;, que em teoria são variáveis imutáveis, mas não se deixe enganar, o &lt;code&gt;const&lt;/code&gt; só funciona assim com tipos &lt;strong&gt;primitivos&lt;/strong&gt;. Com tipos &lt;strong&gt;Object&lt;/strong&gt; ele não permite que você reatribua um novo valor à variável, mas continua permitindo que as propriedades de um objeto já atribuído a ela sejam alteradas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Imutabilidade com Const&lt;/strong&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&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;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Roberto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Error: Assignment to constant variable. &lt;/span&gt;
&lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Roberto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// Error: Assignment to constant variable. &lt;/span&gt;

&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Roberto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// person = { name: 'Roberto' }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Object.seal
&lt;/h4&gt;

&lt;p&gt;O &lt;code&gt;Object.seal&lt;/code&gt; "sela" um objeto, não permitindo que nenhuma propriedade seja removida e nenhuma nova seja adicionada a ele, porém permite que suas propriedades já existentes sejam modificadas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Importante&lt;/strong&gt;: nenhum erro ou warning é retornado quando se tenta mutar um objeto selado.&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;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Roberto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Resultado quando não selado&lt;/strong&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="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Roberto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;90&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;Resultado quando selado&lt;/strong&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="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Roberto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&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;h4&gt;
  
  
  Object.freeze
&lt;/h4&gt;

&lt;p&gt;O &lt;code&gt;Object.freeze&lt;/code&gt; "congela" um objeto, não permitindo que nenhuma propriedade seja removida, nenhuma nova seja adicionada a ele e nem que suas propriedades já existentes sejam modificadas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Importante&lt;/strong&gt;: nenhum erro ou warning é retornado quando se tenta mutar um objeto congelado.&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;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Roberto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Resultado quando congelado&lt;/strong&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;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&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;&lt;strong&gt;"Ah mas então isso é imutabilidade!"&lt;/strong&gt; &lt;/p&gt;

&lt;p width="100%"&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F114883627-7cac5700-9ddb-11eb-9951-1b9178c0dbbf.png" class="article-body-image-wrapper"&gt;&lt;img width="400" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F114883627-7cac5700-9ddb-11eb-9951-1b9178c0dbbf.png" height="400"&gt;&lt;/a&gt; 
&lt;/p&gt;

&lt;p&gt;Assim como no &lt;code&gt;Object.assign&lt;/code&gt; (e no &lt;code&gt;Object.seal&lt;/code&gt;), o &lt;code&gt;Object.freeze&lt;/code&gt; também só vale para as propriedades de primeiro nível do objeto em si, caso uma propriedade seja um objeto &lt;em&gt;nested&lt;/em&gt; ou faça uma referência a um objeto externo seus filhos &lt;strong&gt;poderão&lt;/strong&gt; ser mutados, pois esse objeto não estará congelado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Objetos congelados com propriedades nested&lt;/strong&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;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Self Employed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renato@renatorodrigues.com&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="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jobAtSpaceX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;VP of Mars Colonization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renato.rodrigues@wearecoming.mars&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jobAtSpaceX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;Resultado obtido&lt;/strong&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="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
  &lt;span class="na"&gt;job&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="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Self Employed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.sp@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
    &lt;span class="na"&gt;wage&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="err"&gt; &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Objetos congelados com referência externa&lt;/strong&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;jobAtSpaceX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;VP of Mars Colonization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renato.rodrigues@wearecoming.mars&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jobAtSpaceX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;jobAtSpaceX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;Infinity&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;Resultado obtido&lt;/strong&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="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
  &lt;span class="na"&gt;job&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="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VP of Mars Colonization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@wearecoming.mars&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;
    &lt;span class="na"&gt;wage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ES6 (para Arrays) e E2018 (para Objetos)
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Spread operator
&lt;/h4&gt;

&lt;p&gt;O Spread operador se tornou o meio padrão de conseguir imutabilidade em JS, pois ao &lt;em&gt;"espalhar"&lt;/em&gt; as propriedades de um &lt;code&gt;array&lt;/code&gt; &lt;em&gt;(&lt;a href="https://www.w3schools.com/js/js_es6.asp" rel="noopener noreferrer"&gt;ES6&lt;/a&gt;)&lt;/em&gt; ou &lt;code&gt;objeto&lt;/code&gt; &lt;em&gt;(&lt;a href="https://www.w3schools.com/js/js_2018.asp" rel="noopener noreferrer"&gt;ES2018&lt;/a&gt;)&lt;/em&gt; em um novo array ou objeto, uma cópia é feita, se tornando assim independente do original.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mergeando objetos com o Spread&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&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;var&lt;/span&gt; &lt;span class="nx"&gt;lastNameOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&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;var&lt;/span&gt; &lt;span class="nx"&gt;emailOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&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;var&lt;/span&gt; &lt;span class="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&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;nameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;lastNameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;emailOnly&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// nameOnly = { name: 'Renato' }&lt;/span&gt;
&lt;span class="c1"&gt;// myInfo = { name: 'Renato', lastName: 'Rodrigues', email: 'renato.rodrigues@renatorodrigues.com' }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;"Ah, mas então está aí a imutabilidade 100% em JS"&lt;/strong&gt;&lt;/p&gt;

&lt;p width="100%"&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F114885941-859e2800-9ddd-11eb-8945-8e8b963cf31d.png" class="article-body-image-wrapper"&gt;&lt;img width="680" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F114885941-859e2800-9ddd-11eb-8945-8e8b963cf31d.png" height="658"&gt;&lt;/a&gt; 
&lt;/p&gt;

&lt;p&gt;O Spread Operator é como se fosse uma "versão moderna" do &lt;code&gt;Object.assign({}, N)&lt;/code&gt;. A mesma situação com propriedades nested e referências externas citadas anteriormente também ocorre com o spread.&lt;/p&gt;

&lt;p width="100%"&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F114887631-027dd180-9ddf-11eb-8a5a-aa04590c0412.png" class="article-body-image-wrapper"&gt;&lt;img width="799" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F114887631-027dd180-9ddf-11eb-8a5a-aa04590c0412.png" height="349"&gt;&lt;/a&gt; 
&lt;/p&gt;

&lt;h2&gt;
  
  
  Proxies
&lt;/h2&gt;

&lt;p&gt;Uma das novidades mais interessantes (e menos utilizadas) do &lt;em&gt;ES6&lt;/em&gt; foram os proxies. Podemos dizer que quando se faz proxy de um objeto, ele fica "protegido" por um proxy que tem acesso à leitura e à gravação de suas propriedades e pode manipular como fazê-los. Resumindo, o proxy "esconde" o objeto original e qualquer acesso à ele é feito via métodos especiais chamados de traps. Isso pode ser utilizado juntamente com um padrão que favoreça a imutabilidade do objeto original, como por exemplo o &lt;a href="https://en.wikipedia.org/wiki/Copy-on-write" rel="noopener noreferrer"&gt;copy-on-write&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Funcionamento prático do Proxy&lt;/strong&gt;&lt;/p&gt;

&lt;p width="100%"&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F113735547-b8a43580-96d2-11eb-9c60-659660038bf5.png" class="article-body-image-wrapper"&gt;&lt;img width="519" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F113735547-b8a43580-96d2-11eb-9c60-659660038bf5.png" height="406"&gt;&lt;/a&gt; 
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo Proxy&lt;/strong&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;personObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&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="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// set Trap&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// get Trap&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&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;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&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="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;personProxy&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;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;personObj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;personObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hobbies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video games, running&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;personProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mario&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="s2"&gt;Luigi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// personObj.hobbies = "video games, running"&lt;/span&gt;
&lt;span class="c1"&gt;// personObj.pets = "Mario, Luigi"&lt;/span&gt;

&lt;span class="c1"&gt;// personProxy.hobbies = ["video games", "running"]&lt;/span&gt;
&lt;span class="c1"&gt;// personProxy.pets = ["Mario", "Luigi"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Immer
&lt;/h2&gt;

&lt;p&gt;Fazendo o uso massivo de proxies, a biblioteca &lt;strong&gt;&lt;a href="https://immerjs.github.io/immer/" rel="noopener noreferrer"&gt;Immer&lt;/a&gt;&lt;/strong&gt; surgiu como uma maneira mais simples e direta de garantir a imutabilidade de objetos em JS. Basicamente o que ela faz é proteger o objeto original &lt;em&gt;(olha o Proxy aí \o/)&lt;/em&gt; e persistir cada alteração feita nele num objeto intermediário, chamado de &lt;em&gt;Draft&lt;/em&gt;, para depois no final da operação &lt;em&gt;produzir&lt;/em&gt; um novo objeto com o resultado das alterações do draft aplicadas ao objeto original.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Funcionamento prático da Immer&lt;/strong&gt;&lt;/p&gt;

&lt;p width="100%"&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F113742336-e8563c00-96d8-11eb-9fe7-4ed7bad770ad.png" class="article-body-image-wrapper"&gt;&lt;img width="800" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F113742336-e8563c00-96d8-11eb-9fe7-4ed7bad770ad.png" height="652"&gt;&lt;/a&gt; 
&lt;/p&gt;

&lt;h3&gt;
  
  
  Mas como a Immer funciona?
&lt;/h3&gt;

&lt;p width="100%"&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimmerjs.github.io%2Fimmer%2Fassets%2Fimages%2Fimmer-4002b3fd2cfd3aa66c62ecc525663c0d.png" class="article-body-image-wrapper"&gt;&lt;img width="800" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimmerjs.github.io%2Fimmer%2Fassets%2Fimages%2Fimmer-4002b3fd2cfd3aa66c62ecc525663c0d.png" height="311"&gt;&lt;/a&gt; 
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo sem Immer (muta o objeto original)&lt;/strong&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;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;withCobli&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collaborator&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;collaborator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cobli&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;collaborator&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;employee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withCobli&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// person: { firstName: 'Renato', lastName: 'Rodrigues', company: 'Cobli' } &lt;/span&gt;
&lt;span class="c1"&gt;// employee: { firstName: 'Renato', lastName: 'Rodrigues', company: 'Cobli' } &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Exemplo com Spread (não muta o objeto original)&lt;/strong&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;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;withCobli&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collaborator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;collaborator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;company&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cobli&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="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;employee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withCobli&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// person: { firstName: 'Renato', lastName: 'Rodrigues' } &lt;/span&gt;
&lt;span class="c1"&gt;// employee: { firstName: 'Renato', lastName: 'Rodrigues', company: 'Cobli' } &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Exemplo com Immer&lt;/strong&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;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;withCobli&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collaborator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;draftCollaborator&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;draftCollaborator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cobli&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;employee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withCobli&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// person: { firstName: 'Renato', lastName: 'Rodrigues' } &lt;/span&gt;
&lt;span class="c1"&gt;// employee: { firstName: 'Renato', lastName: 'Rodrigues', company: 'Cobli' } &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Porque Immer?
&lt;/h3&gt;

&lt;p&gt;De acordo com o artigo de introdução à Immer, somente na listagem do &lt;a href="https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md#immutable-update-utilities" rel="noopener noreferrer"&gt;Redux-ecosystem-links&lt;/a&gt; existem outras &lt;strong&gt;67&lt;/strong&gt; bibliotecas de imutabilidade em JS. Então porque usar a Immer?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pequena&lt;/strong&gt;: Somente 3kb e com &lt;strong&gt;ZERO&lt;/strong&gt; dependências;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rápida&lt;/strong&gt;: Utiliza funções nativas de JS, como os proxies, ao invés de loops e condicionais;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simples&lt;/strong&gt;: Pode ser implementada em uma linhas e não requer nenhuma configuração;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versátil&lt;/strong&gt;: Suporta propriedades nested de infinitos níveis e mantem a tipagem correta das propriedades!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fácil&lt;/strong&gt;: Curva de aprendizagem praticamente zero, somente sintaxe nativa de JS, nenhuma outra sintaxe ou padrão é necessário;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparente&lt;/strong&gt;: Uma vez implementada, você mal percebe que está usando;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estruturalmente Equivalente&lt;/strong&gt;: Partes não mutadas do novo objeto vão continuar fazendo referência ao objeto original. Mantendo eles assim equivalentes e evitando a duplicação de informações idênticas na memória.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reducers
&lt;/h2&gt;

&lt;p&gt;No mundo React existe um fluxo obrigatório de como as informações devem ser persistidas e lidas na Store (&lt;em&gt;state&lt;/em&gt;). Esse fluxo é uni-direcional, com passos bem definidos e sempre trabalhando com imutabilidade &lt;em&gt;(viu a chance aí?)&lt;/em&gt;. Ele se aplica tanto ao estado da aplicação &lt;em&gt;(usando Redux)&lt;/em&gt;, quanto ao estado interno dos componentes &lt;em&gt;(usando useReducer)&lt;/em&gt;&lt;/p&gt;

&lt;p width="100%"&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F113736047-2badac00-96d3-11eb-849e-4a77b43994df.png" class="article-body-image-wrapper"&gt;&lt;img width="800" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F113736047-2badac00-96d3-11eb-849e-4a77b43994df.png" height="655"&gt;&lt;/a&gt; 
&lt;/p&gt;

&lt;p&gt;Um reducer nada mais é que uma função que recebe dois parâmetros, o estado atual e uma ação que contém um tipo e pode ou não conter um payload. A partir do tipo da ação é decidido quais mudanças serão aplicadas ao estado da aplicação/componente. Como este estado é &lt;strong&gt;imutável&lt;/strong&gt;, esta função deve retornar uma nova cópia dele já com as diferenças aplicadas. Este então será o novo estado.&lt;/p&gt;

&lt;p&gt;Hoje em dia, grande maioria dos devs utiliza o spread operator para fazer essa cópia do estado atual e modificá-lo sem mutá-lo&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reducer usando spread&lt;/strong&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;demoReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;demoState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;demoActions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;demoState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ActionTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INCREMENT_COUNTER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ActionTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DECREMENT_COUNTER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;decrementCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decrementCount&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ActionTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SET_AMOUNT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Reducer usando spread (erro)&lt;/strong&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;demoReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;demoState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;demoActions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;demoState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ActionTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INCREMENT_COUNTER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Currying
&lt;/h2&gt;

&lt;p&gt;Currying é o processo de transformar uma função que espera vários argumentos em uma função que espera um único argumento e retorna outra função que recebe um argumento e assim sucessivamente até o final dos argumentos. Por exemplo, uma função que recebe três argumentos, vai resultar em uma função que recebe um argumento e retorna uma função que recebe um argumento, que por sua vez retorna uma função que recebe um argumento e retorna o resultado da função original.&lt;/p&gt;

&lt;p&gt;As funções &lt;em&gt;curried&lt;/em&gt; podem tanto receber parâmetros das funções acima quanto os valores retidos nessas funções &lt;em&gt;(closures)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo Currying&lt;/strong&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;function&lt;/span&gt; &lt;span class="nf"&gt;sayTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;who&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;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;who&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;say&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;what&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="s2"&gt;`Say &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;what&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;person&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sayToRenato&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sayTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;sayToRenato&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wasuuuup!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="c1"&gt;// Say Wasuuuup! to RENATO &lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sayToCaio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sayTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Caio&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;sayToCaio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Yo Bro!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;sayToCaio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Whats going on?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Say Yo Bro! to CAIO&lt;/span&gt;
&lt;span class="c1"&gt;// Say Whats going on? to CAIO &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Curried Reducer
&lt;/h2&gt;

&lt;p&gt;Aproveitando as vantagens do currying, os desenvolvedores da Immer criaram o modo curried do método &lt;code&gt;produce&lt;/code&gt;, que cai como uma luva quando usado em um Reducer. Ele recebe como o único parâmetro uma função de callback que vai receber um state e uma &lt;em&gt;action&lt;/em&gt;. O curried reducer irá retornar uma função que ao receber o state original irá criar um draft dele e chamará o callback passando esse draft junto com a action passada pelo Redux/useReducer, criando assim um reducer 100% compatível e completamente transparente para quem o chama. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo Curried Reducer&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Draft&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;immer&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;demoReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Draft&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DemoState&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;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DemoActions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ActionTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INCREMENT_COUNTER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ActionTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DECREMENT_COUNTER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decrementCount&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ActionTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SET_AMOUNT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Sim, é só isso que precisa pra usar, não tem mais nada mesmo)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Como migrar para Immer
&lt;/h2&gt;

&lt;p&gt;1) Importe a função &lt;code&gt;produce&lt;/code&gt; da Immer;&lt;br&gt;
2) Adicione-a no modo &lt;strong&gt;curried&lt;/strong&gt; ao seu reducer ja existente;&lt;br&gt;
3) Remova todos os returns;&lt;br&gt;
4) Remova todos os spreads;&lt;br&gt;
5) Mute as propriedades diretamente;&lt;br&gt;
6) Remova o case default.&lt;/p&gt;

&lt;p width="100%"&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F113737117-21d87880-96d4-11eb-9077-1dda6b4ec910.png" class="article-body-image-wrapper"&gt;&lt;img width="800" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F113737117-21d87880-96d4-11eb-9077-1dda6b4ec910.png" height="450"&gt;&lt;/a&gt; 
&lt;/p&gt;

&lt;h3&gt;
  
  
  Desafios
&lt;/h3&gt;

&lt;p&gt;1) Esquecer o padrão spread;&lt;br&gt;
2) (Re-)aprender a mutar propriedades de um objeto usando JS básico.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Na dúvida sempre lembre-se&lt;/strong&gt;&lt;/p&gt;

&lt;p width="100%"&gt;
    &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F113745551-c01c0c80-96db-11eb-9d3b-a45be55c9c16.png" class="article-body-image-wrapper"&gt;&lt;img width="800" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F484549%2F113745551-c01c0c80-96db-11eb-9d3b-a45be55c9c16.png" height="718"&gt;&lt;/a&gt; 
&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus: Mutações básicas
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Alterar propriedade&lt;/span&gt;
&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Criar propriedade&lt;/span&gt;
&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newProperty&lt;/span&gt; &lt;span class="o"&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;// Excluir propriedade&lt;/span&gt;
&lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uselessProperty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Alterar/criar propriedade nested&lt;/span&gt;
&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nestedObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nestedProperty&lt;/span&gt; &lt;span class="o"&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;// Excluir propriedade nested&lt;/span&gt;
&lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nestedObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uselessNestedProperty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Alterar/criar propriedade nested em um array&lt;/span&gt;
&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nestedArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;nestedProperty&lt;/span&gt; &lt;span class="o"&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;// Adicionar um item ao um array&lt;/span&gt;
&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nestedArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newObj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Excluir propriedade nested em um array&lt;/span&gt;
&lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nestedArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;uselessNestedProperty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Excluir um item ao um array&lt;/span&gt;
&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nestedArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://immerjs.github.io/immer/update-patterns" rel="noopener noreferrer"&gt;Referência completa de mutação em objetos e arrays&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Preciso migrar tudo?
&lt;/h3&gt;

&lt;p&gt;Nop. A menos que queira.&lt;/p&gt;

&lt;h3&gt;
  
  
  Qual o melhor momento para migrar então?
&lt;/h3&gt;

&lt;p&gt;Considerando que a migração é bem simples, eu usaria a seguinte regra: Tem que modificar algo num Reducer? já aproveita a chance e migra.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplos de reducers migrados
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sandbox Demo: &lt;a href="https://codesandbox.io/s/usereducer-demo-e76k0?file=/src/Demo2/state/reducer.ts" rel="noopener noreferrer"&gt;Antes&lt;/a&gt;, &lt;a href="https://codesandbox.io/s/usereducer-demo-with-immer-ite7t?file=/src/Demo2/state/reducer.ts" rel="noopener noreferrer"&gt;Depois&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Apêndice 1: Questões sobre Igualdade de valores e referências
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Igualdade de valores e referências&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;evenNumbers&lt;/span&gt; &lt;span class="o"&gt;=&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;evenNumbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;evenNumbers&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nx"&gt;evenNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;evenNumbers&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="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Igualdade de valores e referências usando filter&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;evenNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&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="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;evenNumbers&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nx"&gt;evenNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;evenNumbers&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="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Igualdade de valores e referências em objetos&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt; &lt;span class="o"&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;v&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;v&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="na"&gt;v&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;v&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;v&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;v&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;v&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;v&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;v&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;v&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;evenNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&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="nx"&gt;item&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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;evenNumbers&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
  &lt;span class="nx"&gt;evenNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
  &lt;span class="nx"&gt;evenNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
  &lt;span class="nx"&gt;evenNumbers&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="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
  &lt;span class="nx"&gt;evenNumbers&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="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;allNumbers&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="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Igualdade de valores e referências com Object.assign&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&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;var&lt;/span&gt; &lt;span class="nx"&gt;lastNameOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&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;var&lt;/span&gt; &lt;span class="nx"&gt;emailOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&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;var&lt;/span&gt; &lt;span class="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastNameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emailOnly&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;myInfo&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="nx"&gt;nameOnly&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="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Igualdade de valores e referências com Object.assign({})&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&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;var&lt;/span&gt; &lt;span class="nx"&gt;lastNameOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&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;var&lt;/span&gt; &lt;span class="nx"&gt;emailOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&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;var&lt;/span&gt; &lt;span class="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastNameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emailOnly&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;myInfo&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="nx"&gt;nameOnly&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="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Igualdade de valores e referências com o spread operator&lt;/strong&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;var&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&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;var&lt;/span&gt; &lt;span class="nx"&gt;lastNameOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rodrigues&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;var&lt;/span&gt; &lt;span class="nx"&gt;emailOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renato.rodrigues@renatorodrigues.com&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;var&lt;/span&gt; &lt;span class="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&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;nameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;lastNameOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;emailOnly&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;myInfo&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="nx"&gt;nameOnly&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="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nx"&gt;myInfo&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nameOnly&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Equality Operator (==) e Strict Equality Operador (===)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Para tipos primitivos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;==&lt;/strong&gt; Compara igualdade de valores &lt;strong&gt;(faz conversões)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;===&lt;/strong&gt; Compara igualdade de valores e tipo &lt;strong&gt;(não faz conversões)&lt;/strong&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&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="c1"&gt;// true&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&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="c1"&gt;// false&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="kc"&gt;undefined&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="c1"&gt;// true&lt;/span&gt;
&lt;span class="kc"&gt;undefined&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="c1"&gt;// false&lt;/span&gt;
&lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Para tipos Object&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;==&lt;/strong&gt; Compara referência (ignora estrutura e valores)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;===&lt;/strong&gt; Compara referência (ignora estrutura e valores)&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;var&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&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;var&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Renato&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;var&lt;/span&gt; &lt;span class="nx"&gt;person3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;person3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;person3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bonus: Igualdade de NaN&lt;/strong&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;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;NaN&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;NaN&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="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&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="c1"&gt;// false&lt;/span&gt;
&lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&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;is&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="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&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;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
