<?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: Shahar Kedar</title>
    <description>The latest articles on DEV Community by Shahar Kedar (@shaharke).</description>
    <link>https://dev.to/shaharke</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F921029%2F018a586a-8643-4211-84fa-ec4f287b451d.png</url>
      <title>DEV Community: Shahar Kedar</title>
      <link>https://dev.to/shaharke</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shaharke"/>
    <language>en</language>
    <item>
      <title>Thoughts on using ChatGPT in job interviews</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Fri, 07 Jun 2024 08:52:59 +0000</pubDate>
      <link>https://dev.to/shaharke/thoughts-on-using-chatgpt-in-job-interviews-1ejo</link>
      <guid>https://dev.to/shaharke/thoughts-on-using-chatgpt-in-job-interviews-1ejo</guid>
      <description>&lt;p&gt;A software developer friend told me yesterday that she had a job interview where she had to do live coding and was not allowed to use ChatGPT. She could search Google for what she needed, but not ask ChatGPT or similar tools. I'm not a big fan of live coding in the first place, but fine. But not using ChatGPT? Why? In my opinion, it's simply a lack of understanding of what the required skillset for developers is in the &lt;del&gt;future&lt;/del&gt; present. To me, it's equivalent to asking in an interview to code in a text editor instead of an IDE. Let me explain.&lt;/p&gt;

&lt;p&gt;A few days ago, a &lt;a href="https://newsletter.pragmaticengineer.com/p/ai-coding-agents?publication_id=458709&amp;amp;post_id=145297550&amp;amp;isFreemail=true&amp;amp;r=1572ms&amp;amp;triedRedirect=true"&gt;new article&lt;/a&gt; was published in The Pragmatic Engineer where he talks about AI Software Agents. Software agents know how to use language models to solve software problems autonomously and almost without human intervention. In a recent experiment conducted by researchers at Princeton University, software agents were able to correctly solve 12.5% of the tickets given to them completely independently. That's crazy. And this is after just 6 months of work by a team of only 7 people. Imagine what a company like Cognition Labs (the company behind Devin.ai), which received $175 million in funding, will manage (or already has) to do in the same timeframe. &lt;/p&gt;

&lt;p&gt;Note that I wrote that software agents worked "almost" without human intervention. It seems that at least for now*, there are two places where human involvement is required - (1) defining the problem and (2) reviewing the solution. It also appears to be an iterative process where (1) and (2) run in a loop until a good enough solution is reached. As of today, the people who have the most suitable skillset and knowledge to operate software agents are ...&lt;strong&gt;drum roll&lt;/strong&gt;... developers.&lt;/p&gt;

&lt;p&gt;How does all this relate to job interviews? Even if we work with Princeton's numbers, it effectively means that the rate of solving at least 12.5% of software companies' software problems can be accelerated by orders of magnitude. In other words, all other things being equal, a company that encourages its developers to use software agents has a significant advantage over a company that doesn't. And if that is indeed the case, then a company that does not test the ability of developers to actively use tools like ChatGPT is effectively missing a critical skillset for the company's success.&lt;/p&gt;

&lt;p&gt;By allowing the use of ChatGPT, the screening process would simulate a more realistic development scenario. Candidates could engage the AI assistant as they would when actually working, using it as a knowledgeable resource and collaborator to help break down problems, propose solutions, and refine their code.&lt;/p&gt;

&lt;p&gt;The true skills being evaluated then become the abilities to properly frame problems, ask the right questions, and critically analyze the information or code snippets provided by ChatGPT. These higher-level skills of problem decomposition, communication, and critical thinking are arguably more important than brute memorization of syntax and algorithms.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm betting that even this will be replaced by AI agents in the near future, but that's for another post. Maybe.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Potential objections
&lt;/h2&gt;

&lt;p&gt;(Thanks to &lt;a href="https://x.com/davidshimon"&gt;David Shimon&lt;/a&gt; for raising interesting objections)&lt;/p&gt;

&lt;h3&gt;
  
  
  Objection #1:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;When we interview developers, we're not looking to test if they know how to use ChatGPT because that's relatively easy and we assume they'll be ok with it. On the other hand, using ChatGPT might mask other abilities that the candidate may be lacking. If we use the IDE analogy, in an interview it's not interesting to test if the candidate knows how to use an IDE as it is to see them write code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I disagree with this objection on several levels:&lt;br&gt;
First, using ChatGPT is easy. But using it &lt;strong&gt;effectively&lt;/strong&gt; isn't. At least for now, developers need to make sure ChatGPT doesn't hallucinate too much, writes quality code, and one that's suited to the technologies used at the company. Crafting the right prompt and improving it iteratively is no easy task. &lt;/p&gt;

&lt;p&gt;Like I said, observing a candidate use ChatGPT live can provide valuable insights into their thought process. I argue that incorporating ChatGPT into the interview presents a better opportunity to assess how a candidate approaches problems than a traditional coding exercise. The focus shifts away from merely testing technical coding proficiency towards evaluating problem-solving skills, code review abilities, and the iterative refinement of solutions. With a sufficiently complex exercise, the interviewer could dive into more advanced aspects of programming that are seldom explored when a candidate must write all the code from scratch.&lt;/p&gt;

&lt;p&gt;Lastly, live coding is a rather stressful setting already and necessarily time-boxed. In such a session, we want to lower as many barriers as possible that would unnecessarily slow the candidate down without being related to their day-to-day work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Objection #2:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Many companies already have tried-and-tested exercises for screening candidates, but using ChatGPT would make them too easy. Starting to modify exercises just to allow ChatGPT isn't worth the investment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This argument is irrelevant for new companies or those seeking to update their existing coding exercises. In my experience, many companies don't stick to a single exercise for years; instead, they adapt it to align with rapidly evolving technology requirements. As for the remaining companies, if their exercise can be easily solved using ChatGPT, it may indicate that the exercise is evaluating the wrong skills. For instance, numerous companies today assess algorithmic knowledge through "LeetCode"-style problems, which are rarely applicable to the day-to-day tasks of 99% of programmers. While ChatGPT, assuming no hallucinations, can trivialize such algorithmic questions, one must question the value these questions provided in the first place.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have more objections? Drop a comment!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>interview</category>
      <category>software</category>
      <category>ai</category>
    </item>
    <item>
      <title>TIL: What is a Balint group?</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Sat, 25 May 2024 07:49:10 +0000</pubDate>
      <link>https://dev.to/shaharke/til-what-is-a-balint-group-4hok</link>
      <guid>https://dev.to/shaharke/til-what-is-a-balint-group-4hok</guid>
      <description>&lt;p&gt;Yesterday, my wife casually mentioned a term I wasn't familiar with - &lt;a href="https://www.americanbalintsociety.org/what_is_a_balint_group.php"&gt;&lt;em&gt;Balint group&lt;/em&gt;&lt;/a&gt;. A Balint group is a method of clinical supervision for doctors, started by the psychoanalysts Michael and Enid Balint in the 1950s in London. The aim is to help doctors better understand the psychological and emotional aspects of the doctor-patient relationship. In a Balint group session, a doctor presents a case involving a challenging patient. The group discusses the emotional dynamics and tries to understand the patient's inner experience and motivations, rather than focusing just on medical solutions.&lt;/p&gt;

&lt;p&gt;It wouldn't be the first time I learned something new from my wife. What was surprising to me was that, without really knowing, I had participated in a form of a Balint group for two years and led one myself for the past year as part of an initiative called Downleft. I just never realized there was a professional term for what we were doing.&lt;/p&gt;

&lt;p&gt;In Downleft, we form peer groups (e.g., tech leads) from different tech companies that meet on a monthly basis and share dilemmas from their work. Each session, a different participant presents a dilemma or a challenge they have, and a lot of what's happening next is not discussing solutions (which is something tech people love to do), but rather surfacing the organizational and personal dynamics that underpin the situation.&lt;/p&gt;

&lt;p&gt;The meeting format is as follows: the presenter gives a 5-10 minute overview of their dilemma, then we go around the table and do a "questions round". During this round, participants are allowed only to ask questions and not give any other input. Once the round is over, we do another round where participants can give their input, share their experiences, or offer tips.&lt;/p&gt;

&lt;p&gt;I've noticed two kinds of dynamics that are super interesting to see. Firstly, the questions round is no less useful than the second round. I've seen presenters starting to deeply reflect on their situation and come up with meaningful insights only by answering questions. Secondly, other members of the group often share their own similar dilemmas, validating many of the feelings and frustrations the presenter is having. I'm always amazed by how powerful this peer-validation process is.&lt;/p&gt;

&lt;p&gt;I'm pretty sure that when Downleft was conceptualized by &lt;a href="https://www.linkedin.com/in/orenellenbogen/"&gt;Oren Ellenbogen&lt;/a&gt;, he was not aware of Balint groups, but the similarity is so striking that I would have to ask him if he was inspired by it. Surprisingly, Downleft is pretty unique in the tech industry. One would expect that such a simple and powerful format would be more widely adopted, but I'm pretty sure that is not the case. If you're reading this and familiar with similar types of groups, please leave a comment!&lt;/p&gt;

</description>
      <category>downleft</category>
      <category>psychology</category>
      <category>todayilearned</category>
      <category>tech</category>
    </item>
    <item>
      <title>Why chess super computers do not excite me, but LLMs do</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Fri, 17 May 2024 17:29:16 +0000</pubDate>
      <link>https://dev.to/shaharke/why-chess-super-computers-do-not-excite-me-but-llms-do-3ja1</link>
      <guid>https://dev.to/shaharke/why-chess-super-computers-do-not-excite-me-but-llms-do-3ja1</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is my humble attempt to share a random "shower thought."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Chess is an amazing game. For me, it's one of the top strategy games ever invented. So why am I not excited when I think about chess supercomputers? Why am I not amazed by this grand technology the same way I'm amazed by grandmasters?&lt;/p&gt;

&lt;p&gt;I think the answer is that chess supercomputers have only a single application - playing chess. [Chess software is also great for learning chess, but I'm pretty sure you don't need a supercomputer to learn chess. Just to beat grandmasters. Please prove me wrong.]&lt;/p&gt;

&lt;p&gt;But wait, there are many inventions that have only a single application that are exciting (e.g., penicillin), so what's the difference? The difference is that it's quite impressive to see people playing chess at the highest level, while it's not really impressive (for me) to see a computer playing chess at the highest level. Just like it doesn't impress anyone (anymore) that computers run complex arithmetic computations at the blink of an eye.&lt;/p&gt;

&lt;p&gt;LLMs, on the other hand, are very exciting. Language is another skill that humans possess that, up until recently, was hard for computers to successfully imitate. To some extent, LLMs can do amazing things with language that humans can't (or can't do as fast as computers). However, what's more exciting to me is the countless applications that humans can build on top of LLMs. It was amazing to hear the hubbub of ideas thrown around the office, on social networks, or practically everywhere I went when people started to use ChatGPT. It felt as if humans unlocked something in their minds that up until that point was only constrained by their imagination. For me - that's beautiful (as well as terrifying, but that's for a different post).&lt;/p&gt;

</description>
      <category>chess</category>
      <category>technology</category>
      <category>showerthoughts</category>
    </item>
    <item>
      <title>Avoid stupid mistakes with type Branding and Flavoring</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Sun, 07 Apr 2024 05:49:12 +0000</pubDate>
      <link>https://dev.to/shaharke/avoid-stupid-mistakes-with-type-branding-and-flavoring-1g8p</link>
      <guid>https://dev.to/shaharke/avoid-stupid-mistakes-with-type-branding-and-flavoring-1g8p</guid>
      <description>&lt;p&gt;In a structural type system like TypeScript, functions that accept multiple arguments of the same type can sometimes lead to unexpected behavior. This is because TypeScript only considers the structure of the arguments, not their explicit type names, when determining type compatibility.&lt;/p&gt;

&lt;p&gt;Here's an example that illustrates this potential issue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blogId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PostId&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;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;blogId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;postId&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// this code line compiles, but doesn't work correctly&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blogId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  What can we do about it?
&lt;/h1&gt;

&lt;p&gt;Thanks to &lt;a href="https://x.com/davidshimon"&gt;David&lt;/a&gt;, a colleague of mine, I've recently learned about two new techniques to avoid this problem - &lt;strong&gt;Branding&lt;/strong&gt; and &lt;strong&gt;Flavoring&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Branding
&lt;/h2&gt;

&lt;p&gt;Branding in TypeScript is a technique that allows you to create distinct types from any existing type, whether it's a primitive type (like string, number, or boolean) or a complex type (like an object, interface, class, or function). Branding is a form of nominal typing, which contrasts with TypeScript's default structural typing behavior.&lt;/p&gt;

&lt;p&gt;With branding, you can introduce &lt;a href="https://en.wikipedia.org/wiki/Nominal_type_system"&gt;nominal typing&lt;/a&gt; for specific types in your codebase, ensuring that values representing different concepts or entities cannot be mixed accidentally, even if they share the same underlying structure or primitive type.&lt;/p&gt;

&lt;p&gt;Let's see how this is done with our previous example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Branding a string&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PostId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BlogId&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;postId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;PostId&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;blogId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-456&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blogId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PostId&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;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;blogId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;postId&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Doesn't compile&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blogId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we brand the &lt;code&gt;string&lt;/code&gt; type by using an intersection type with an object literal that has a special &lt;code&gt;__brand&lt;/code&gt; property. &lt;code&gt;PostId&lt;/code&gt; and &lt;code&gt;BrandId&lt;/code&gt; are distinct branded types, even though their underlying primitive type is &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we are using an input validation library like &lt;a href="//zod.dev"&gt;Zod&lt;/a&gt;, we can avoid casting when branding values:&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;PostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PostId&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;BlogId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BlogId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Branding a string&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;PostId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PostId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post-123&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;blogId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-456&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;(checkout &lt;a href="https://dev.to/shaharke/zod-zero-to-hero-chapter-1-5bna"&gt;my blog posts series on Zod&lt;/a&gt; if you are not familiar with it)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While branding is useful for preventing careless mistakes, such as passing an incorrect value to the wrong positional argument of a function, it is not a foolproof solution It merely shifts the responsibility of properly constructing and branding values to the point where they are created. We can still make mistakes at that stage and inadvertently brand an incorrect value.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with Branding
&lt;/h2&gt;

&lt;p&gt;Branding has one caveat: we can no longer assign values to variables directly without 'blessing' them, either through casting or using a library like Zod. This can be problematic when writing tests or working with auto-generated code. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PostId&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;postId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This code doesn't compile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This issue is thoroughly explained in &lt;a href="https://spin.atomicobject.com/typescript-flexible-nominal-typing/"&gt;this great article&lt;/a&gt; and I highly recommend reading it. In the article, we are introduced to the &lt;em&gt;Flavor&lt;/em&gt; solution. In short, flavoring is similar to branding but allows implicit conversion, addressing the issue we discussed earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Flavoring&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlavorT&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;_type&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;FlavorT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Flavor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FlavorT&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;Flavoring&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlavorT&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;type&lt;/span&gt; &lt;span class="nx"&gt;PostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Flavor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PostId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This code compiles&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Flavor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BlogId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blogId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// But this still doesn't&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this works is perfectly explained in the original article, so I'll just quote it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TypeScript won’t let us mix our ID types because, under the hood, the &lt;code&gt;_type&lt;/code&gt; properties are incompatible. The optional string "PostId" is not assignable to the optional string "BlogId". But because the &lt;code&gt;_type&lt;/code&gt; is optional, implicit conversion from unflavored values of the same underlying type is allowed. Once implicit conversion happens, however, TypeScript will henceforth treat the value as potentially having the declared &lt;code&gt;_type&lt;/code&gt; and disallow mixing with other, differently flavored types. Thus, downstream consumers of the value will get the safety and semantic benefits.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Using Flavor with Zod
&lt;/h2&gt;

&lt;p&gt;An immediate question arises: can we use Flavors with Zod? When using Zod, we first define a schema, and then infer types based on that schema. How can we use the &lt;code&gt;Flavor&lt;/code&gt; type we wrote above as part of our Zod schemas? &lt;/p&gt;

&lt;p&gt;To achieve that, we need to understand refining in Zod. Zod's refine method allows you to define a custom validation function for a schema, enabling you to enforce more complex validation rules beyond the built-in validations provided by Zod.&lt;/p&gt;

&lt;p&gt;Here's a basic example of using Zod's &lt;code&gt;refine&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&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;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Define a schema for a user's age&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ageSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;refine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&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;User must be at least 18 years old&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="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="k"&gt;try&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;validAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ageSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Valid age&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;validAge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 20&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;invalidAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ageSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Invalid age&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: User must be at least 18 years old&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first argument of the &lt;code&gt;refine&lt;/code&gt; method is a function that accepts a single argument, the validated input - a &lt;code&gt;number&lt;/code&gt; in this case, and returns a &lt;code&gt;boolean&lt;/code&gt;. Interestingly, if we pass a &lt;a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards"&gt;Type Guard function&lt;/a&gt;, the parsed input type is narrowed based on the type predicate defined for the type guard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Flavor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BlogId&lt;/span&gt;&lt;span class="dl"&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;function&lt;/span&gt; &lt;span class="nf"&gt;isBlogId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;id&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;BlogId&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;id&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;BlogIdSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;refine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isBlogId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// The type of value is BlogId and not string&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BlogIdSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123&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;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;TypeScript is a structural type system, meaning it doesn't prevent us from passing an incorrect value to a function if the value's type matches the function parameter's type. A common technique to address this issue is Branding, which distinguishes between values with the same structure. While branding is useful, it makes value construction somewhat cumbersome. Flavoring is a more advanced approach that allows implicit conversion for easily constructing values while maintaining type safety. Zod provides built-in support for Branding. For Flavoring, we need to leverage type guard functions and Zod's refine method.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>programming</category>
      <category>zod</category>
    </item>
    <item>
      <title>Schema Extension and Reuse</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Sat, 30 Mar 2024 11:23:46 +0000</pubDate>
      <link>https://dev.to/shaharke/schema-extension-and-reuse-clc</link>
      <guid>https://dev.to/shaharke/schema-extension-and-reuse-clc</guid>
      <description>&lt;p&gt;TypeScript truly shines in large projects where we frequently encounter a wide array of complex types. To tackle such complexity, two commonly used strategies are &lt;em&gt;inheritance&lt;/em&gt; and &lt;em&gt;composition&lt;/em&gt;. These approaches encourage code reuse by allowing us to leverage existing functions and types across different code paths. By doing so, we establish a single source of truth for business logic and data models, fostering consistency and maintainability throughout the codebase. &lt;/p&gt;

&lt;h2&gt;
  
  
  Inheritance vs Composition
&lt;/h2&gt;

&lt;p&gt;Inheritance is a concept where a new type (child) inherits properties and methods from an existing type (parent). On the other hand, composition is a way of combining types or objects together into a new type.&lt;/p&gt;

&lt;p&gt;For example, let's say we have a &lt;code&gt;Person&lt;/code&gt; type and an &lt;code&gt;Employee&lt;/code&gt; type that extends from &lt;code&gt;Person&lt;/code&gt;. With inheritance, &lt;code&gt;Employee&lt;/code&gt; inherits all properties and methods from &lt;code&gt;Person&lt;/code&gt;, and we can add additional properties or methods specific to &lt;code&gt;Employee&lt;/code&gt;. This is achieved using the extends keyword:&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;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Employee&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;employeeId&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="nl"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With composition, we create new types by combining existing types together. Instead of inheriting properties from a parent type, we create a new type that contains instances of other types as properties. This is often done using object literals or interfaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;street&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="nl"&gt;city&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="nl"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PersonDetails&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, the &lt;code&gt;PersonDetails&lt;/code&gt; type is composed of properties like &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;age&lt;/code&gt;, as well as an instance of the &lt;code&gt;Address&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;Just like in TypeScript, Zod also enables us to reuse schemas whether by extending them or composing them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The .extend() Method
&lt;/h2&gt;

&lt;p&gt;The core of Zod's extension functionality is the &lt;code&gt;.extend()&lt;/code&gt; method available on every schema instance. This method allows us to create a new schema based on an existing one while adding, removing, or transforming properties.&lt;/p&gt;

&lt;p&gt;Here's a basic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&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;zod&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;Base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;positive&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;ExtendedSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ExtendedType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;extendedSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Equivalent to { name: string; age: number; email: string; }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, we start with a &lt;code&gt;Base&lt;/code&gt; that defines &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;age&lt;/code&gt; properties. We then use &lt;code&gt;.extend()&lt;/code&gt; to create a new schema &lt;code&gt;ExtendedSchema&lt;/code&gt; that includes all properties from &lt;code&gt;Base&lt;/code&gt; and adds an &lt;code&gt;email&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;Beyond adding new properties, &lt;code&gt;.extend()&lt;/code&gt; also allows us to override existing properties from the base schema. This can be useful when we want to apply additional validation rules.&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;OverriddenSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;positive&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;Here, we extend &lt;code&gt;Base&lt;/code&gt; but override the age property to enforce that it must be a positive integer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The .pick() and .omit() Methods
&lt;/h2&gt;

&lt;p&gt;Sometimes, we may want to create a new schema by picking or omitting certain properties from an existing schema. Zod provides the &lt;code&gt;.pick()&lt;/code&gt; and &lt;code&gt;.omit()&lt;/code&gt; methods for this purpose.&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;PickedSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pick&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="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// Equivalent to z.object({ name: z.string() })&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OmittedSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;omit&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="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// Equivalent to z.object({ name: z.string() })&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Schema Composition
&lt;/h2&gt;

&lt;p&gt;The simplest form of schema composition, is using existing schemas for defining properties of other schemas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&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;zod&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;Address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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;PersonDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Address&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;Zod also allows us to merge multiple schemas together using the .merge() method. This can be handy when we have different schema fragments that we want to combine.&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;Schema1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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;Schema2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;positive&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;MergedSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Schema1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Schema2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Equivalent to z.object({ name: z.string(), age: z.number().positive() })&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively we can use the &lt;code&gt;.and&lt;/code&gt; method to create a slightly more readable code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MergedSchema = Schema1.and(Schema2);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Merge vs Extend
&lt;/h2&gt;

&lt;p&gt;When should we use &lt;code&gt;merge&lt;/code&gt; and when &lt;code&gt;extend&lt;/code&gt;? We can always use &lt;code&gt;merge&lt;/code&gt; instead of &lt;code&gt;extend&lt;/code&gt;. However, in many cases, it would be an overhead to define an independent schema just to extend an existing schema. If, however, the extension is likely to be used independently, we should probably use &lt;code&gt;merge&lt;/code&gt; from the beginning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extending Union Schemas
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/shaharke/zod-zero-to-hero-chapter-4-513c"&gt;the previous chapter&lt;/a&gt; we talked about Zod unions and discriminated unions. One gotcha with unions is that they lack the &lt;code&gt;.extend&lt;/code&gt; method. So how do we extend union schemas? We use the &lt;code&gt;.and&lt;/code&gt; method:&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;Success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;literal&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="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&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="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;literal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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;Result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;discriminatedUnion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&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;Success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;// The following code does not compile&lt;/span&gt;
&lt;span class="c1"&gt;// const HttpResult = Result.extend( { httpStatus: z.number()}) &lt;/span&gt;

&lt;span class="c1"&gt;// Use .and instead&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HttpResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;httpStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;()}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Schema extension through inheritance and compositions is a powerful feature allowing us developers to really use Zod as a single source of truth for our types. &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>zod</category>
      <category>programming</category>
      <category>node</category>
    </item>
    <item>
      <title>Union Types</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Tue, 26 Mar 2024 19:25:33 +0000</pubDate>
      <link>https://dev.to/shaharke/zod-zero-to-hero-chapter-4-513c</link>
      <guid>https://dev.to/shaharke/zod-zero-to-hero-chapter-4-513c</guid>
      <description>&lt;p&gt;In previous chapters I used pretty rudimentary schemas that involved mostly primitives. In reality our code is going to be much more complex, requiring complicated schemas to represent possible input. &lt;/p&gt;

&lt;p&gt;The next few chapters will deep dive into some more complex schema examples. We will start with union types. &lt;/p&gt;

&lt;h2&gt;
  
  
  What are union types good for?
&lt;/h2&gt;

&lt;p&gt;Union types are used to express a value that can be one of several types. There are many examples for the usefulness of union types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A function parameter that can be either a &lt;code&gt;string&lt;/code&gt; or a &lt;code&gt;number&lt;/code&gt; can be defined using a union type as &lt;code&gt;string | number&lt;/code&gt;. This is especially useful when dealing with values that might come from different sources or in different formats but can be handled by the same piece of code.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&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;ul&gt;
&lt;li&gt;They are ideal for modeling data structures that might hold different types under different conditions. For example, we might have a response from an API that can either be an object representing data or an error message string. In fact, we can see this pattern in Zod's &lt;code&gt;safeParse&lt;/code&gt; API:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;SafeParseSuccess&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Output&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;SafeParseError&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We can achieve type structure polymorphism with union types. This is very powerful combined with &lt;a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html"&gt;type narrowing&lt;/a&gt;, enabling a form of runtime type inspection and branching logic that resembles polymorphic behavior in traditional OOP, where different code paths can be taken based on the actual type of an object.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Bird&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Bird&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bird&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;chirp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;makeSound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dog&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;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bark&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;woof&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;whimper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat&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;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meow&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meow&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;purr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bird&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;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chirp&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chirp&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;tweet&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;h2&gt;
  
  
  Defining union schemas with Zod
&lt;/h2&gt;

&lt;p&gt;Just like with types, we can create schemas which are a union of two or more schemas:&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;StringOrNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;union&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;()]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For convenience, you can also use the &lt;code&gt;.or&lt;/code&gt; method:&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;StringOrNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unions are not reserved only to primitive types. You can easily create a union of objects:&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;Success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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;Result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;union&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Discriminated unions
&lt;/h2&gt;

&lt;p&gt;Zod unions are useful but not very efficient. When we evaluate a value against a union schema, Zod will try to use all options to parse it, which could become quite slow. Not only that, if it fails, it will provide all the error from all the validations. &lt;/p&gt;

&lt;p&gt;For example, if we run the following code:&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="nx"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;foo&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;We will get the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZodError: [
  {
    "code": "invalid_union",
    "unionErrors": [
      {
        "issues": [
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "value"
            ],
            "message": "Required"
          }
        ],
        "name": "ZodError"
      },
      {
        "issues": [
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "message"
            ],
            "message": "Required"
          }
        ],
        "name": "ZodError"
      }
    ],
    "path": [],
    "message": "Invalid input"
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Discriminated unions provide a more efficient and user friendly way for parsing objects, by allowing us to define a &lt;em&gt;discriminator key&lt;/em&gt; to determine which schema should be used to validate the input.&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;Success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;literal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;literal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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;Result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;discriminatedUnion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status&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;Success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, we use the &lt;code&gt;status&lt;/code&gt; property to discriminate between different input types. Let's see what happens now when we try to validate against an invalid input:&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="nx"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&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="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;foo&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;This time we get a concise error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZodError: [
  {
    "code": "invalid_type",
    "expected": "string",
    "received": "undefined",
    "path": [
      "value"
    ],
    "message": "Required"
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another fun part of using discriminated unions is that we can now use type narrowing to handle inputs:&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;A word of warning:&lt;/em&gt; while discriminated unions are very powerful, there's an &lt;a href="https://github.com/colinhacks/zod/issues/2106"&gt;ongoing discussion&lt;/a&gt; on whether discriminated unions should be deprecated and replaced with a different API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Union types in TypeScript is a powerful way of expressing type variability. Zod enables us to define union schemas quite easily. We should consider using discriminated unions in Zod for better performance and user friendly errors. &lt;/p&gt;

&lt;p&gt;In our next chapter we will explore schema extension. &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>zod</category>
      <category>programming</category>
    </item>
    <item>
      <title>Thoughts on Pair Programming</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Sun, 24 Mar 2024 19:29:29 +0000</pubDate>
      <link>https://dev.to/shaharke/thoughts-on-pair-programming-1i8g</link>
      <guid>https://dev.to/shaharke/thoughts-on-pair-programming-1i8g</guid>
      <description>&lt;p&gt;I am currently leading a team of four very talented engineers, and we started practicing pair programming more often in the past few months. To be completely honest, my initial motives for pairing was mostly personal growth. I was happy to see though that not only was my team happier, but they were also more productive. I've known and practiced pair programming a lot in the past, but only recently have I given it some more serious thought.&lt;/p&gt;

&lt;p&gt;A lot has been written over the years about pair programming. I'm not even sure if this is still a "thing" or a long-forgotten practice (if you're practicing this regularly, do tell!). But since people keep writing about it, I'll assume it's live and kicking. Unfortunately, the general vibe is that some people need to convince other people that pair programming is productive. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3r95k4tl0dc3igz1x1py.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3r95k4tl0dc3igz1x1py.png" alt="Pair vs Meetings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Honestly, I don't want to be part of the conversation. If you're not convinced that there's some merit to pair programming, you're welcome to stop reading now. I'm here to preach to the choir - because honestly it's more fun - and talk about something else: &lt;strong&gt;when does it make sense to pair with someone?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Certainty
&lt;/h2&gt;

&lt;p&gt;As engineers we need to deal a lot with (un)certainty. Sometimes our job is to take a well defined task and implement it in a well defined architecture - high level of certainty. I would argue that in those cases we want to optimize for &lt;strong&gt;execution time&lt;/strong&gt;. The quicker it gets into production and into the hands of customers the better. &lt;/p&gt;

&lt;p&gt;In other cases, we receive a task with a lot of uncertainty. Either the task is not well-defined technically or from a product perspective, the architecture does not exist or doesn't fit, or there are other risks we identify early on. In my opinion, in those cases we want to optimize for &lt;strong&gt;clarity&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;"Wait what? Why not also execution time?" you might ask. You wouldn't be wrong. As a business, especially as a startup, we always want to deliver as fast as possible. &lt;em&gt;BUT&lt;/em&gt; there's also a price for running too fast especially with high degree of uncertainty. We might deliver the wrong thing, deliver a buggy or a poorly performant feature. We might, god forbid, have to write it all over again. And that affects execution time in a very sneaky way that's hard to identify and mitigate. &lt;/p&gt;

&lt;p&gt;So... creating clarity. I think that should be our number one priority. Turn uncertainty into certainty as fast as possible so we can get back to optimizing execution time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pair programming in high certainty tasks
&lt;/h2&gt;

&lt;p&gt;There are two cases, in my opinion, when pairing in high-certainty tasks makes sense:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The engineer who owns the task is not proficient enough&lt;/strong&gt; - this usually happens with junior developers. Even though the task is well defined and poses little risk, there's a chance that a junior engineer will still not do it fast enough. Since we're optimizing for execution time, we need to find a solution. IMHO pair programming is an amazing solution for that. Not only it reduces deliver time, it also increases the junior developer's mastery - 2 at the price of 1. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The engineer who owns the task is proficient but not familiar with the code base&lt;/strong&gt; - in this case pair programming has a simple goal: &lt;em&gt;reduce ramp up time&lt;/em&gt;. Depending on the case, we could restrict the pairing to last only until the owner "gets it" and can continue solo. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Pair programming in low certainty tasks
&lt;/h2&gt;

&lt;p&gt;Here the level of proficiency or knowledge plays a significantly smaller role. It is my belief that it's always worth pairing on low certainty tasks. Pairing serves different purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Quickly identifying blindspots&lt;/strong&gt; - many engineers tend to simply start writing code as a way of thinking about their task. I know I do that a lot. This often creates a "tunnel vision" where we think more about the code we're writing then the task we were given. Having another brain that's not occupied with writing code, really helps surface blindspots early on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast feedback loop&lt;/strong&gt; - one of the biggest advantages of pair programming in general is that we have a partner with whom we can bounce ideas around and zero in on the right solution quickly. With low certainty tasks we need that level of feedback and creativity, because we're almost sure to reach obstacles a lot. When there's no dedicated person to work with, we often spend a lot of idle time waiting for someone to become available. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Psychological commitment&lt;/strong&gt; - sometimes when we're faced with a really difficult task, we tend to wander to other tasks on our plate that are easier (or death-scrolling on social media apps). This behaviour creates a lot of context switching and lengthens delivery times. When pairing we are committed to working on the task at hand. We have little chance to lose our focus. We also have the ability to switch roles if we become tired. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of the above can significantly reduce delivery time while increasing quality. Theocratically, we could have done two different tasks in parallel - but the result would have been poorer and not necessarily faster. &lt;/p&gt;

&lt;h2&gt;
  
  
  What now?
&lt;/h2&gt;

&lt;p&gt;Now I need to start practicing what I preach. I'm going to try and intentionally use the "certainty" criteria to decide if pair programming is necessary. I'm also going to try and find other criteria that I can apply consistently. I would love to hear your thoughts - what criteria do you use? &lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>pair</category>
    </item>
    <item>
      <title>Input Sanitation</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Fri, 22 Mar 2024 07:06:52 +0000</pubDate>
      <link>https://dev.to/shaharke/zod-zero-to-here-chapter-3-182b</link>
      <guid>https://dev.to/shaharke/zod-zero-to-here-chapter-3-182b</guid>
      <description>&lt;p&gt;Zod has a really nice feature that allows us to define, for schemas that describe objects, how properties not defined in the schema should be treated. We can choose one of 3 modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strip: Zod will strip out unrecognized keys during parsing. This is the default behaviour.&lt;/li&gt;
&lt;li&gt;Passthrough: Zod will keep unrecognized keys and will not validate them.&lt;/li&gt;
&lt;li&gt;Strict: Zod will return an error for any unrecognized key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three modes have their uses, but in this post I will focus on &lt;code&gt;strip&lt;/code&gt; and &lt;code&gt;strict&lt;/code&gt;, who can help with what is called "Input Sanitation".&lt;/p&gt;

&lt;h2&gt;
  
  
  What is input sanitation?
&lt;/h2&gt;

&lt;p&gt;Input sanitation is a critical security practice aimed at preventing malicious users from injecting harmful data into our software. This practice involves validating and cleaning up the data received from the user before processing or storing it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Example scenario: unauthorized account modification
&lt;/h3&gt;

&lt;p&gt;Imagine a web application that allows users to update their profile information, including their email but not their user role, which is intended to be controlled only by administrators. The application receives an object with the fields to be updated and directly passes it to the database query without properly sanitizing the input to remove or restrict fields.&lt;/p&gt;

&lt;p&gt;Vulnerable code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/updateProfile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Assuming req.body is something like {email: "newemail@example.com"}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// The ID of the currently logged-in user&lt;/span&gt;

    &lt;span class="c1"&gt;// Update the user profile with the provided fields&lt;/span&gt;
    &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;updateOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;updates&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;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// handle error&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="c1"&gt;// success&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;An attacker discovers this endpoint and decides to send a modified request that includes an additional property, &lt;code&gt;role&lt;/code&gt;, in an attempt to escalate their privileges:&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;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"attacker@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&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;By sending this payload, the attacker could potentially change their user role to "admin", assuming the application does not properly check the fields that are being updated. This happens because the database command directly uses the object from the request, allowing any properties provided to be included in the &lt;code&gt;$set&lt;/code&gt; operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can Zod help?
&lt;/h2&gt;

&lt;p&gt;We can use one of the modes mentioned above to prevent this attack. Let's see what would be the behavior of each mode:&lt;/p&gt;

&lt;h3&gt;
  
  
  Strip
&lt;/h3&gt;

&lt;p&gt;Strip is the default mode of every schema and does not require any explicit configuration. We can change the vulnerable endpoint above in the following way:&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;Updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/updateProfile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Updates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// log updates to see the result&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="s2"&gt;You shall not pass!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&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;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

    &lt;span class="c1"&gt;// Update the user profile with the provided fields&lt;/span&gt;
    &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;updateOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;updates&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;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// handle error&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="c1"&gt;// success&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;Now when an attacker sends the following body:&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;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"attacker@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&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;Zod will strip the &lt;code&gt;role&lt;/code&gt; property from the body before passing it on to the update statement. We should expect to see the following log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You shall not pass! { "email": "attacker@example.com" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Strict
&lt;/h3&gt;

&lt;p&gt;We can also configure a schema to be strict, causing unrecognized keys to throw an error:&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;Updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// ... rest of code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now calling the endpoint with the malicious payload will result in the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZodError: [
  {
    "code": "unrecognized_keys",
    "keys": [
      "role"
    ],
    "path": [],
    "message": "Unrecognized key(s) in object: 'role'"
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the context of input sanitation for security, using &lt;code&gt;strict&lt;/code&gt; could be useful if we are looking to identify security breaches attempts as they happen. &lt;/p&gt;

&lt;p&gt;Another interesting option is to use a mix of &lt;code&gt;strict&lt;/code&gt; and &lt;code&gt;strip&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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;StrictUpdates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Updates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/updateProfile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parseResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StrictUpdates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;parseResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;parseResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issue&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;ZodIssueCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unrecognized_keys&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unrecognized keys in updates&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;updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Updates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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="s2"&gt;You shall not pass!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// ... rest of code&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that usage of &lt;code&gt;safeParse&lt;/code&gt; instead of &lt;code&gt;parse&lt;/code&gt; when using the &lt;code&gt;StrictUpdates&lt;/code&gt; schema. &lt;code&gt;safeParse&lt;/code&gt; allows us to validate input without throwing an error in case the input is invalid. In this case we use &lt;code&gt;safeParse&lt;/code&gt; to identify and log unrecognized keys, but not fail the request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Input sanitation is a very common and important security measure. Zod can help sanitize inputs in different ways - by silently dropping unrecognized keys or by throwing errors. &lt;/p&gt;

&lt;p&gt;&lt;a href="-%20[Chapter%204:%20Union%20Types](https://dev.to/shaharke/zod-zero-to-hero-chapter-4-513c)"&gt;Next chapter&lt;/a&gt; we will learn how to define union types with Zod.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>typescript</category>
      <category>node</category>
      <category>zod</category>
    </item>
    <item>
      <title>Input Validation</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Sun, 17 Mar 2024 07:25:34 +0000</pubDate>
      <link>https://dev.to/shaharke/zod-zero-to-hero-chapter-2-3dge</link>
      <guid>https://dev.to/shaharke/zod-zero-to-hero-chapter-2-3dge</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2n0d6d3oexlqxul0crkd.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2n0d6d3oexlqxul0crkd.jpeg" alt="Input validation meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the previous chapter I used a boring example for using Zod. It was boring because there was no external input involved. Zod is useful when we need to deal with data, whose shape (and therefore type) is only determined in runtime and the TypeScript compiler can't keep us safe. A very common example is when handling incoming HTTP requests. For example:&lt;/p&gt;

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

const UserSchema = z.object({
  name: z.string(),
  age: z.number(),
  email: z.string().email(),
});
type User = z.infer&amp;lt;typeof UserSchema&amp;gt;;

async function createUser(req: Request, res: Response): Promise&amp;lt;void&amp;gt; {
  const userData: User = UserSchema.parse(req.body);
  const newUser = await saveUser(userData);
  res.json(newUser);
}


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

&lt;/div&gt;

&lt;p&gt;We get two main benefits by using Zod:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We can validate our input using Zod's built-in and tested validation logic. The &lt;code&gt;createUser&lt;/code&gt; function will fail if the &lt;code&gt;email&lt;/code&gt; property contains a random string.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;userData&lt;/code&gt; is typed. We don't need to use casting (god forbid!) to work with the correct type in our application logic. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why should I care about input validation?
&lt;/h2&gt;

&lt;p&gt;Well... there are many good reasons but for starters it keeps your code &lt;strong&gt;secure&lt;/strong&gt;, preventing code injection hacks and the like, but it also keeps you code &lt;strong&gt;less prone to unusual bugs&lt;/strong&gt;. I feel like security has been discussed a lot so I'm not going to talk about that here. But the latter reason is as important IMHO.&lt;/p&gt;

&lt;p&gt;There are a few questions we should ask ourselves:&lt;/p&gt;

&lt;h3&gt;
  
  
  Where do we rather catch an error?
&lt;/h3&gt;

&lt;p&gt;I would argue that it's best to catch an error &lt;strong&gt;as close as possible to the source of the error&lt;/strong&gt;. If the code is very simple, that might not be important, but if we run complex logics and/or transactions, catching the error at the beginning might prevent weird or critical bugs related to state inconsistency etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  What kind of error do we prefer?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwiz4yoc21zdl5a8snm8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwiz4yoc21zdl5a8snm8j.png" alt="Error meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've been working with JavaScript for a while you're probably familiar with the infamous "Uncaught TypeError: Cannot Read Property of Undefined" error. I really hate when that happens! And really it could be easily avoided with Zod and the right schema. &lt;/p&gt;

&lt;p&gt;Lets see this in action. First we'll change our HTTP handler to not use Zod and run some basic logic:&lt;/p&gt;

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

async function createUser(req: Request, res: Response): Promise&amp;lt;void&amp;gt; {
  const user: User = req.body;
  processEmail(user);
  res.status(200).end();
}

function processEmail(user: User) {
  if (user.email.split("@")[1].endsWith("gmail.com") {
    doSomethingGoogly(user);
  } else {
    doSomethingElse(user)
  }
}


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

&lt;/div&gt;

&lt;p&gt;What kind of error would we get if &lt;code&gt;req.body&lt;/code&gt; doesn't contain an &lt;code&gt;email&lt;/code&gt;?&lt;/p&gt;

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

TypeError: Cannot read properties of undefined (reading 'split')


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

&lt;/div&gt;

&lt;p&gt;Did I already mention that I hate this error? 🤬&lt;/p&gt;

&lt;p&gt;What kind of error would we get with Zod?&lt;/p&gt;

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

ZodError: [
  {
    "code": "invalid_type",
    "expected": "string",
    "received": "undefined",
    "path": [
      "email"
    ],
    "message": "Required"
  }
]


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

&lt;/div&gt;

&lt;p&gt;Nice!&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Zod becomes useful when you need to validate external input. One very common use case is when handling incoming HTTP requests. Zod is cool because it infers types out of schemas and allows you to use those types in your business logic. Assuming your schema is correct, the TypeScript compiler guarantees that correct input will be handled correctly. No surprises.&lt;/p&gt;

&lt;p&gt;Input validation is important because it prevents bugs from happening deep in our code and provides meaningful error messages that's easier to understand and solve.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/shaharke/zod-zero-to-here-chapter-3-182b"&gt;Next chapter&lt;/a&gt; would be on how to sanitize incoming HTTP requests with Zod.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>programming</category>
      <category>zod</category>
    </item>
    <item>
      <title>Introduction to Zod</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Wed, 13 Mar 2024 06:56:55 +0000</pubDate>
      <link>https://dev.to/shaharke/zod-zero-to-hero-chapter-1-5bna</link>
      <guid>https://dev.to/shaharke/zod-zero-to-hero-chapter-1-5bna</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpeh3ce2tf7p5av777dm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpeh3ce2tf7p5av777dm.png" alt="Zod Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was first introduced to &lt;a href="https://zod.dev/" rel="noopener noreferrer"&gt;Zod&lt;/a&gt; by &lt;a href="https://github.com/bobrowadam" rel="noopener noreferrer"&gt;Adam Bobrow&lt;/a&gt; - a colleague of mine and a dear friend. Adam was sick and tired from JavaScript's brittleness, and about two years ago he started migrating our code base to TypeScript. But that wasn't enough for him. He kept complaining: "What good are my types, if some other service decides to send me bad data and breaks my code?". That's when he discovered Zod. &lt;/p&gt;

&lt;p&gt;At first I thought: "Yah yah, yet another input validation library. We already use Joi." 5 minutes later I was convinced. Zod was not yet another input validation library. It does something extra, but very important, that other libraries don't do - &lt;strong&gt;it infers types out of schemas&lt;/strong&gt; 🪄 .&lt;/p&gt;

&lt;p&gt;The purpose of this series is to walk you through using Zod from the very basics to plugging it into every I/O operations your system does - making it de-facto strongly typed.&lt;/p&gt;

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

&lt;p&gt;Zod is a TypeScript library used for creating schemas to validate data types. It helps ensure that the data our program receives or works with matches the expected format, like checking if a variable is a number, a string, or a more complex object with specific properties. Zod is particularly useful because it's designed with TypeScript's type system in mind. It allows developers to define schemas that not only validate the shape and type of data at runtime but also automatically infer TypeScript types from these schemas.&lt;/p&gt;

&lt;p&gt;Let's look at a basic example:&lt;/p&gt;

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

import { z } from 'zod';

// Define a schema for the user
const UserSchema = z.object({
  name: z.string(),
  age: z.number(),
  email: z.string().email(),
});

// Create a user data object to validate
const userData = {
  name: 'John Doe',
  age: 30,
  email: 'john.doe@example.com',
};

// Validate the user data against the schema
const validationResult = UserSchema.safeParse(userData);

if (validationResult.success) {
  console.log('Validation succeeded:', validationResult.data);
} else {
  console.log('Validation failed:', validationResult.error);
}


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

&lt;/div&gt;

&lt;p&gt;The above example is not very exciting since it's not that different from what we could do with other validation libraries. To make it interesting, let's add some type inference to the mix.&lt;/p&gt;

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

import { z } from 'zod';

// Define a schema for the user
const UserSchema = z.object({
  name: z.string(),
  age: z.number(),
  email: z.string().email(),
});

// This is where the magic happens..
type User = z.infer&amp;lt;typeof UserSchema&amp;gt;;

// Create a user data object to validate
const userData = {
  name: 'John Doe',
  age: 30,
  email: 'john.doe@example.com',
};

// Validate the user data against the schema
const user: User = UserSchema.parse(userData);


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

&lt;/div&gt;

&lt;p&gt;Notice how Zod automatically inferred the type User out of UserSchema. Why is that a big deal? &lt;strong&gt;Because it creates a single source of truth for all our types&lt;/strong&gt; and enforces any external input to conform to that source of truth. Other schema validation libraries will force us to manually define types and keep those types in sync with our schemas. Here's an example of how we would do it with Joi:&lt;/p&gt;

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

import * as Joi from 'joi';

// Define a schema for the user with Joi
const UserSchema = Joi.object({
  name: Joi.string().required(),
  age: Joi.number().required(),
  email: Joi.string().email().required(),
});

type User = {
  name: string;
  age: number;
  email: string;
};

// Create a user data object to validate
const userData = {
  name: 'John Doe',
  age: 30,
  email: 'john.doe@example.com',
};

// Validate the user data against the schema
const { value } = UserSchema.validate(userData);

// Cast value to User
const user: User = value;


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

&lt;/div&gt;

&lt;p&gt;One clear difference is that we had to define the User type ourselves in addition to the schema. Unfortunately that also means that changing the schema does not force us to change the type or vice versa. So let's assume that we've added the &lt;code&gt;address&lt;/code&gt; property to User but haven't changed the schema:&lt;/p&gt;

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

type User = {
  name: string;
  age: number;
  email: string;
  address: string; // &amp;lt;- new property
};


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

&lt;/div&gt;

&lt;p&gt;Our original code will continue to compile but the following code will fail in runtime:&lt;/p&gt;

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

const userData = {
  name: 'John Doe',
  age: 30,
  email: 'john.doe@example.com',
};

const { value } = UserSchema.validate(userData); // &amp;lt;- validation passes
const user: User = value;

console.log(user.address.toUpperCase()); // &amp;lt;- but this line fail miserably


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

&lt;/div&gt;

&lt;p&gt;With Zod, to change the type we would need to change the schema (single source of truth), ensuring that any bad input is validated before we reach any significant business logic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/shaharke/zod-zero-to-hero-chapter-2-3dge"&gt;Next&lt;/a&gt; in our series, we'll use Zod to validate input from HTTP requests. &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>programming</category>
      <category>zod</category>
    </item>
    <item>
      <title>Using self-signed certificates when developing Android applications</title>
      <dc:creator>Shahar Kedar</dc:creator>
      <pubDate>Mon, 05 Sep 2022 17:36:23 +0000</pubDate>
      <link>https://dev.to/shaharke/using-self-signed-certificates-when-developing-android-applications-2i9e</link>
      <guid>https://dev.to/shaharke/using-self-signed-certificates-when-developing-android-applications-2i9e</guid>
      <description>&lt;p&gt;I recently started learning how to develop mobile applications on Android. I've been doing mostly backend work before I joined RiseUp, but in the past 2 years I've learned to love web development, and mobile development seemed like a natural next step.&lt;br&gt;
 &lt;br&gt;
The first three weeks were awesome! Google created an amazing set of hands-on tutorials you can do to get started. But then I wanted to test my skills with real-world scenarios, and decided to implement our login flow in Android. The flow itself is not that interesting so I won't go into details there. What's important is that we use Nginx in our local (dev) environment to funnel all requests to our backend services. Nginx is responsible not only for routing API calls to the right service, but also for SSL termination. This allows our backend services to avoid meddling with SSL termination on their own.&lt;br&gt;
 &lt;br&gt;
Our local Nginx listens to port 9090, so I thought something like this should work pretty well*:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;loginApiService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Retrofit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://localhost:9090"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LoginApiService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                                

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loginApiService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;*I simplified the code to make it more concise. &lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But when I ran the application, I got the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;java.net.ConnectException: Failed to connect to localhost/127.0.0.1:9090
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Say what??? Well… apparently localhost on mobile devices is the device itself. That actually makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem no.1 - forwarding calls to localhost to my laptop
&lt;/h2&gt;

&lt;p&gt;What I really wanted is that any calls to &lt;code&gt;localhost&lt;/code&gt; should go to my laptop and not the device. &lt;code&gt;adb&lt;/code&gt; to the rescue!&lt;/p&gt;

&lt;p&gt;Android Debug Bridge (adb) is a CLI tool that helps you communicate with your mobile devices (virtual or physical). You can easily install in using brew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;android-platform-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It has a cool command called &lt;code&gt;reverse&lt;/code&gt; that allows you to forward any calls from any device to your laptop. This is how it's done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adb reverse tcp:9090 tcp:9090
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This basically tells the device that every TCP call on port 9090 should be forwarded to port 9090 on your laptop. &lt;/p&gt;

&lt;p&gt;Problem solved! So I ran my application again and this time I got this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Problem no.2 - telling your device to trust a self-signed certificate
&lt;/h2&gt;

&lt;p&gt;Our local Nginx uses a self-signed SSL certificate. It was created by an &lt;code&gt;openssl&lt;/code&gt; command. This worked great for web development and we didn't have any real issues with it so far.  &lt;/p&gt;

&lt;p&gt;With Android (and iOS) devices, you need to tell your device to trust that certificate. There are two steps here:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 - Install a CA certificate on the device
&lt;/h3&gt;

&lt;p&gt;First you need to tell your device to trust the root CA of your self signed certificate. Unfortunately, when using &lt;code&gt;openssl&lt;/code&gt; to generate a certificate, you don't really have a root CA. So first I needed to change that. &lt;/p&gt;

&lt;p&gt;I searched the Internet and found a great tool called &lt;a href="https://github.com/FiloSottile/mkcert"&gt;mkcert&lt;/a&gt;. &lt;code&gt;mkcert&lt;/code&gt; is a simple tool for making locally-trusted development certificates (I shamelessly copied from their README. Sue me).&lt;/p&gt;

&lt;p&gt;When using &lt;code&gt;mkcert&lt;/code&gt; you also get a PEM encoded CA Certificate which is exactly what our Android device is expecting. To find that certificate you can 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;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;mkcert &lt;span class="nt"&gt;-CAROOT&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/rootCA.pem"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the certificate to your device. Now on your device open the _CA Certificate _ settings screen and follow the instructions to install the certificate you copied. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 - Tell your application to trust user added CAs
&lt;/h3&gt;

&lt;p&gt;By default, Android applications will not trust user added CAs. To make it trust your certificate you need to create a new file under &lt;code&gt;res/xml&lt;/code&gt; called &lt;code&gt;network_security_config&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;network-security-config&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;debug-overrides&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;trust-anchors&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- Trust preinstalled CAs --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;certificates&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"system"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- Additionally trust user added CAs --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;certificates&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/trust-anchors&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/debug-overrides&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/network-security-config&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we're trusting user added certificates only in debug mode. Released applications should work against properly signed SSL certificates. &lt;/p&gt;

&lt;p&gt;Now add the configuration file to your AndroidManifest file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt;   
&lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;android:networkSecurityConfig=&lt;/span&gt;&lt;span class="s"&gt;"@xml/network_security_config"&lt;/span&gt;
&lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! 🎉&lt;/p&gt;

&lt;p&gt;P.S. This works well for both physical and virtual devices.&lt;/p&gt;

&lt;p&gt;To summarize, in order to enable your Android application to connect with an HTTPs server on your laptop with a self-signed certificate, you should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;adb&lt;/code&gt; to forward all calls to localhost&lt;/li&gt;
&lt;li&gt;Generate a root CA certificate and install in on your device&lt;/li&gt;
&lt;li&gt;Tell your application to trust user added CAs&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>android</category>
      <category>ssl</category>
      <category>nginx</category>
    </item>
  </channel>
</rss>
