<?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: Andrew Philips</title>
    <description>The latest articles on DEV Community by Andrew Philips (@codeedog).</description>
    <link>https://dev.to/codeedog</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%2F1070968%2Fa3ec6f21-c792-4126-a2fe-e45375a7d9cc.jpeg</url>
      <title>DEV Community: Andrew Philips</title>
      <link>https://dev.to/codeedog</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/codeedog"/>
    <language>en</language>
    <item>
      <title>Narrowing Multiple Return Types in TypeScript</title>
      <dc:creator>Andrew Philips</dc:creator>
      <pubDate>Mon, 01 May 2023 02:01:44 +0000</pubDate>
      <link>https://dev.to/codeedog/narrowing-multiple-return-types-in-typescript-398o</link>
      <guid>https://dev.to/codeedog/narrowing-multiple-return-types-in-typescript-398o</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// multiple return types&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;withCitrus&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="nx"&gt;Apples&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Why can't we write this?! We know Oranges are returned&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;withCitrus&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;// error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Function &lt;code&gt;getFruit&lt;/code&gt; fetches us a bag of Apples or Oranges. At compile time, as developers we know the function returns Oranges because we asked for them. Unfortunately, the compiler doesn't know this. To fix the error, the standard recommendation is to use a &lt;a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates"&gt;Type Guard&lt;/a&gt; to narrow the type. This requires extra and seemingly unnecessary 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="c1"&gt;// type guard distinguishes between Apples and Oranges&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;isOranges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Apples&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;VitaminC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Apples&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;withCitrus&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isOranges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// type guard narrowed the type to Oranges&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="na"&gt;oranges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ok, no compilation error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The thing is &lt;strong&gt;we know the returned fruit type at compile time&lt;/strong&gt;; why should we use a type guard? Can we skip it? To do that, we need to rewrite the &lt;code&gt;getFruit&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;In this &lt;a href="https://dev.to/maurerkrisztian/typesafe-multiple-return-types-wuith-typescript-54j9"&gt;article&lt;/a&gt; Maurer Krisztián shows how to use a Generic to connect a function's arguments to its return type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FruitType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;withCitrus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Apples&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;withCitrus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;Oranges&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;withCitrus&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="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;FruitType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;apples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nx"&gt;Apples&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;withCitrus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// ok&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;oranges1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;withCitrus&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;// ok&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;oranges2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;                    &lt;span class="c1"&gt;// ok&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using Krisztián's formulation, we see at compile time how options passed to &lt;code&gt;getFruit&lt;/code&gt; narrow the return type to that of the expected type. This is a great start, let's continue building upon it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid Type Casting
&lt;/h3&gt;

&lt;p&gt;When we implement the function definition returning &lt;code&gt;FruitType&amp;lt;T&amp;gt;&lt;/code&gt; we find it requires an internal type cast (ugh). If we add an overload function, we can continue to narrow the return type while separating it from the implementation. Here's a &lt;a href="https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgIIAd0BsIGdkDeAsAFDLnIID2AruAFzIg0C2ARtADSkWVVZUojAERQIAE2HIAPsmEBzMRBBTZwgJ4QsAgO7DuJAL4BuUqVCRYiFAHkocEPLyEeFanTCNm7Lq-LUBITlBBydVOUUIZX0-ZAA1YDA4FlAAYUYwKBoIAxMzEgtoeCRkAEkAMSzEm3QwYCoQfGIyCh1EgAtUxKzcAH5GNip+CAdc0xJSakawZAARAFFy1ABVABkAFQB9coAlZdKtmwAFdeQAXkJkNrBO7ppcDKyUPImSKdwZjGwIAGVk74eaEwOHwFwIfA8jAAzJw+IERGJJMhDMg4Ph3mBxhjkHZQr9-iDGLjHM4wRCGMgACywgKCEQhEn6eKJZJpR7ZZGo9END7jUhgdToFCVGiJdaCiAAHnWAD5zrFThAAB6QEDiJpXDpdTL3RjwLC4Z7IXpAgHIegK5DK1Xqy7XW46wE6lCyOjiCAwUASTkm4lOfAWlrkP14PkkAD04eQ8ygUEEpEjyHFQuQAHIviCZDj7CTcKnkMB8CAqDM0bhgPIQHA2DhkGAqHWJWmRWKJdKZamAHQJqPkZModPAvD5wtMEtc8uV6u1+uNlOpltgfvtrsACgATFD1+vSDA6Ag6g1kE4wIvpVaVcpbRUqmAaofGjLV1Ran1GOsAJSMRfL2WkZq8NimwvmAoJ2lqdxOk8sLtGiqT8HSwQ5mEsKdmhIH4C8sRiGANBQCAyDAa+nb2tqPTGtmeJ-CwZqMBm+I0SC4yGPkib9pQaKlgAblQwC2tAcZQLCbA0DMCAOMg7R8SgJbtNAVqxoIuC7vuD7HhAp63psADqWqcee1pXvgN6inetT1I+z6vv0SZfsgP5tn+JAAW4PIzERoHnOBNxkbqdbQZJcEIUEwgMihyBoZ2GHImGvA4XhBGrh5uAkRBjoUSG1G0aaOBZSCH5cvZt6-jKzGsVG5SqRZyBUFx0ACHA4gcbUeHOOgcZClAc7ODoUm1jhcCgKA8jdcguBwDAGnqCpIAHtVJ6LjpHQ2HVUANeIBmXmqxmLveFm4E+GE2Z+37FY5pUzXNR4LVpuk3Ct9VUI1VmgTZJnVOZPIfv+sRAdFZKkZB7I5IFuDwfCSF4kykXRVhQbIPF+HIElGGpT5kEZchDHZfReV4B+ZUkEAA"&gt;TS Playground&lt;/a&gt; showing the error and the overload.&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;IOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;withCitrus&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;const&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_FRUIT_OPTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;withCitrus&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="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;IOptions&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;FruitType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;IOptions&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;_opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_FRUIT_OPTS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;opts&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;_opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withCitrus&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;bagOfOranges&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bagOfApples&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Allow Other Options
&lt;/h3&gt;

&lt;p&gt;Adding another option does not interfere with return type narrowing.&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;IOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;withCitrus&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="nx"&gt;hasColor&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Apples&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;apples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nx"&gt;Apples&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;withCitrus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hasColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;   &lt;span class="c1"&gt;// ok&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;oranges1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;withCitrus&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="na"&gt;hasColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// ok&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;oranges2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;hasColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;                      &lt;span class="c1"&gt;// ok&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Can We Always Narrow?
&lt;/h3&gt;

&lt;p&gt;Regardless of how well we refine the TypeScript, there are still some situations when the return type cannot be narrowed.&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;var&lt;/span&gt; &lt;span class="nx"&gt;opts5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;withCitrus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;          &lt;span class="c1"&gt;// boolean&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;apple5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Apples&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        &lt;span class="c1"&gt;// error&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;opts6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;withCitrus&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;// boolean&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;orange6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// error&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;opts7&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;withCitrus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;apple7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Apples&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        &lt;span class="c1"&gt;// ok&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When assigning an object to a variable, TypeScript generalizes the object. &lt;code&gt;opts5&lt;/code&gt; gets type &lt;code&gt;{ withCitrus: boolean }&lt;/code&gt; and therefore the return type is &lt;code&gt;Apples | Oranges&lt;/code&gt;. This is the same result for &lt;code&gt;opts6&lt;/code&gt;. For &lt;code&gt;opts7&lt;/code&gt;, we use &lt;code&gt;as const&lt;/code&gt; to convert the object to a &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-inference"&gt;type literal&lt;/a&gt;, and we once again have return type narrowed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge Case Typing
&lt;/h3&gt;

&lt;p&gt;We have a couple of potential edge cases with the type definition of &lt;code&gt;FruitType&amp;lt;T&amp;gt;&lt;/code&gt; that can cause some bugs: (1) single source of truth for the default option value and (2) triggering a &lt;a href="https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types"&gt;Distributive Conditional Type&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See this &lt;a href="https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgIIAd0BsIGdkDeAvgNwCwAUKJLIigPJRwgDmehpllYAnuigDEoAV2BgAKnwgAecQD5kAXkrJk45BAAekEABN8BZAHcxACwDCYkbgD8ALmSgY0ZACFkRZDZWrkAIwB7AJxmDW0IPXx3G2RGZjZ8AB80TBx8Ox9Vdy0dfWRhPQgYUAhdZGSwERQYuNZ2DIpfFOx6n1qE8gouCgB6ACpkAFFdNmRzOFw8boFgKFwwABpkMFMUXSK4YSwwZAA3OCxhFACYZAADSqOzxxBzgBFBgVQAVQAZcQB9AQAlZ4BJT70AAK4gAygA6EwrSyXXDXAC2wnmyHhcDACFM3FW50uEGuoGW2LOQlEEik13WxRAYmAAVuEUqPHO2XCkXyhSppXKyyqXliTDqcPBlG+EAAjqIoKAWIS8CgwEYAnsDkd8GAlX4UABrCDoHYE3A8EAIZAIKAQNHsUIBTABKBgApiJkwO3+YQsXDCiiobamALu0zGFAIf1YMq6AIIYTwhmE4D4c0S2YQGPgJZGFC4P1bMrmoxSyDnEliST8a7q5DmrA8Sh05APJ5vT4-f6AkEQqEWKxI5DMXRLFbQCB+HhLM0WwtwZC4aU4af+qBIZAnHnCFZeyjibGTEN6Ry4XBHffIJOFw9+MBzvsaCZMivw+O4BxGVa3M5OFyuCkQGgPkDsVxKHjc5AmCC0QDOcEQKCEIIOPKdHTrFcLl5ZJ4CwSZIOQP5bhWYCEAmCB0xQUw4F2FA4EoO540qYA-DXYByLGOldBpOkDjUKRkAAbQARgAXSgrdgLgGBnAQMB8D9IxZRuGgQA4gAKHcWIASmWaAFKgGsKBtaA0VdYCIH2Q5LV0KC-h2UjMAiNUlXNB0oFw7EQygc0JOWLiCTw-AZwdNFaRAL07l1CJWNYfJ0DrQdkDYf8pRNXh+HySYygrdZfxKWSHOEJzPP4AdTHw0MynHS1KCneiWCgn0Vn9FhAxAAIdnmBLLyZf8kAPOBtOQF0oDjfAtDgeEWiWHAwAAcnwMiAmANKpRYNgpVYCrbkQBB5oZDjWNauiGLpBwzm40DYP4sJcnwbjXHOmJwXuyDul45AAFpkFMMAwHQJ8eh6Ix-vBJK8DNYA9SweJwTtFgegjBBcB6Ui9FArUegAJh6XdWLAQKDheoHPQ++EsAAYl22j6Ox8iXsxtiFKwPGpFwSg+h6bpd2RBsXneL5fgBD5gTBJRCGMMwYWsBxcQ8Xt8HZsBOm4LjizJfgZk0UpZAUZRGjUC6woMEXoW7WwHA-Ab3E8bxtdUE6YPA86cj1nibr5dp2GSDAWnSTI3F1tkCkpEoygqKQV05psedbfn20hUWja8b3XfSZo0mQBpVETzogA"&gt;TS Playground&lt;/a&gt; for a deeper explanation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Form
&lt;/h3&gt;

&lt;p&gt;Tying it all together.&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;FruitType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;withCitrus&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Apples&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;B&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_FRUIT_OPTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withCitrus&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="nx"&gt;Oranges&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Apples&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;Oranges&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;IOptions&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;FruitType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getFruit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;IOptions&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;_opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_FRUIT_OPTS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;opts&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;_opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withCitrus&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;bagOfOranges&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bagOfApples&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;Find the complete code and tests for return type narrowing in this &lt;a href="https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgIIAd0BsIGdkDeAsAFDLnIID2AruAFzIg0C2ARtADSkWVVZUojAERQIAE2HIAPsmEBzMRBBTZwgJ4QsAgO7DuJAL4BuUqVCRYiFAHkocEPLyEeFanTCNm7Lq-LUBITlBBydVOUUIZX0-ZAA1YDA4FlAAYUYwKBoIAxMzEgtoeCRkAEkbdDBgKhB8YjIKHUSAC1TErNwAfkY2Kn4IBwNeZrhcVP5BbrRMHFwAbQByAMEFgF0ZZDtQvEXlqDXc0xJSalqwZAARAFEAMVQAVQAZABUAfRuAJXvSt5sABWeAGVkABeQjIJpgVrtGi4DJZFCGZCjPhnI75U64c4YbAQQHJXH4UHIOYEPgeRgAZk4fECIjEkmQhk4ZPcDGQAFYaXsRJFokyWeT2QB2bkTIIaLS6KSGdYozFgI4Kzb2Rx4gmzYmkoWeZAAFjFdOCqrCNISSRSIHSyEy2QFrNo7IAbIbBLylCozYlkml4XbZcj8Ar0SQwOp0CgbllEs9wxAADzPAB8oNiz2QEAAHpAQOI6hCWm1bV1GKAYNBkAAhJnITqxXhzXr9BzrLM5vMkyvrToq7b4WQ4zX0esUatt5QdujiCAwUASDZhiNUGCXW4PF7vL4-V7-IEAOkh0OLtd7avww4avHIg+cF94WzPIdIMDoCCqNWQTjAUZoiUTSYACioSopnTcdc3wcpKmqWoT3TLwIAAN2gABKRgfxjON-yOF8QDfGDPwgb9ozAIDKhLMoKnfWoUNIepeGVV5gLAfAwTJPcOOuO4njeT5vl+AFARpDi92Y-A8mOS9kDEMAaCgEBkAAkdyCY8iD0LGF8DrKT7xNdUWEJOYHycfEDNmPdZ1zUpcyzIDQRTABCVSWL3EYxnFGRZCoPc9lBMFnNwVzRnGQIUPWO8r2vGZ9MMm9TMJCzQHEazp0zOyQUcgKgvcwJPOQbzfJBfyxOykLBDC2IUKOQx8kQuAoGRaLcAARkYaZCXIMEvww0iCEPIsOkYeAsFwCBDCq0g6oauAmoAJjam8iS6oieoAvqNOLIa4BGnJkDcsqJQZYRxqOKb8r0lrGGM5xluI39ev6zS-TGiaSDOkIz3m08nFYwi7sSADXvei7KSui7iW6ki1v28V3SiFQTsm+rzr7PUwb7CGVqh9aoQG2FGCnGc53ERHJNIAB6cnkCuTMNQgK6AGkCyhZBhtGxT5RqLEaSwRJoG22i3uRsTiTJR7NtZ7bRppGGjQUD1jsDVEsVO5HHj5+wsDa3hFsx-7SLEoHkesyxRvwmp0JI2MI3jKDqNwJNVYai4ZzgGgsF1K8euthNCcsiRHfySnqdpsz6epqAoEEZnmmQJscAcRTFxQYB8CcEB+awMVpwhQQAGtcEF97yOa0WY7xuFJZ2mXgthiIFaVhUJLOrNWvazVbtWsTmqqyLeGD6Ao6gJGGrAdA2+T5d8pL9Tcc04w+-7qn44GEAg6pmm6cYK5I+jw8476BOFIA5PkFTwiM817OUB0fPC5H6eWK+u2YN+sWNsGm0ESZJ2M0zL7rq-UhvdMiT9e6LwHrvYeklg6bzDozGOX87QAU5mcHmGsBYPzEpSMu4tP5s0RI3LmioH5ZlBu3G6f0u7kUpOAiBVMqB5wxFzfoe4BDyDWgAcQ9DeRgrcaTXWunw-+NIPgSF4X-SkpMgA"&gt;TS Playground&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article we explain how to narrow a function's multiple return types using its argument list; we show how to inform the compiler which return type the caller expects. We do this in a type safe manner and avoid superfluous type casting. We encourage extra steps to avoid bugs when changing types and defaults. Finally, we explore various edge cases where return type narrowing requires extra focus by using type literals or type guards.&lt;/p&gt;

&lt;p&gt;Please comment below and let me know what you think.&lt;/p&gt;

</description>
      <category>typescript</category>
    </item>
  </channel>
</rss>
