title: React: conditional rendering and discrimination union
body: <p><strong>Goal</strong></p>
  <p>Simplify the following situation</p>
  <pre><code>// Simplify
  loading ? &lt;Loading/&gt; : (
    &lt;Fragment&gt;
      ....
    &lt;/Fragment&gt;
  ) 
  
  // Into something like
  &lt;LoadingContent loading={loading}&gt;
   {() =&gt; (
     &lt;Fragment&gt;
       ...
     &lt;/Fragment&gt;
   )}
  &lt;/LoadingContent&gt;
  </code></pre>
  <p><strong>Problem</strong></p>
  <p>if the loading condition is an attribute of an object, used for <a href="https://basarat.gitbook.io/typescript/type-system/discriminated-unions" rel="nofollow noreferrer">discriminated union</a>, access properties based on this attribute being true will not be infered, and it'll not compile.</p>
  <p><strong>Current solution</strong></p>
  <p>Use short circuit the evaluation with logical &amp;&amp;, but it duplicate the condition and the aim is to make it simpler.</p>
  <pre><code>&lt;LoadingContent loading={loading}&gt;
   {() =&gt; loading &amp;&amp; (
     &lt;Fragment&gt;
       ...
     &lt;/Fragment&gt;
   )}
  &lt;/LoadingContent&gt;
  </code></pre>
  <p><strong>From proposal:</strong></p>
  <p>Problem, generic type must be specified and can't be inferred due to <a href="https://github.com/microsoft/TypeScript/issues/16597" rel="nofollow noreferrer">https://github.com/microsoft/TypeScript/issues/16597</a></p>
  <pre><code>interface LoadingDiscriminatedContentProps&lt;
    A extends string,
    S,
    SS extends S,
    O extends { [P in A]: S }
  &gt; {
    object: O;
    attribute: A;
    discriminant: SS;
    children: (loaded: Extract&lt;O, O &amp; { [P in A]: SS }&gt;) =&gt; React.ReactElement;
  }
  
  export function LoadingDiscriminatedContent&lt;
    A extends string,
    S,
    SS extends S,
    O extends { [P in A]: S }
  &gt;({
    object,
    attribute,
    discriminant,
    children
  }: LoadingDiscriminatedContentProps&lt;A, S, SS, O&gt;): React.ReactElement {
    if (object[attribute] === (discriminant as S)) {
      return children(object as Extract&lt;O, O &amp; { [P in A]: SS }&gt;);
    }
    return &lt;Loading /&gt;;
  }
  </code></pre>