<p dir="auto"><strong>Do you want to request a <em>feature</em> or report a <em>bug</em>?</strong><br>
Request a feature</p>
<p dir="auto">Per some discussion today with <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/tomocchino/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/tomocchino">@tomocchino</a> and <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/thejameskyle/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/thejameskyle">@thejameskyle</a>, I'd like a non-Flow mechanism to annotate what type(s) of elements a component expects to render.</p>
<p dir="auto">Here's some examples, with Flow types for comparison (that I realize may not be currently checked in Flow, yet):</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function Foo({ yes }){
  return yes ? &lt;Bar /&gt; : &lt;div /&gt;;
}
Foo.renderTypes = [Bar, 'div'];


class Bar extends React.Component {
  static renderTypes = [Button];

  render() {
    return &lt;Button /&gt;;
  }
}"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-v">Foo</span><span class="pl-kos">(</span><span class="pl-kos">{</span> yes <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">{</span>
  <span class="pl-k">return</span> <span class="pl-s1">yes</span> ? <span class="pl-c1">&lt;</span><span class="pl-ent">Bar</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span> : <span class="pl-c1">&lt;</span><span class="pl-ent">div</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>
<span class="pl-v">Foo</span><span class="pl-kos">.</span><span class="pl-c1">renderTypes</span> <span class="pl-c1">=</span> <span class="pl-kos">[</span><span class="pl-v">Bar</span><span class="pl-kos">,</span> <span class="pl-s">'div'</span><span class="pl-kos">]</span><span class="pl-kos">;</span>


<span class="pl-k">class</span> <span class="pl-v">Bar</span> <span class="pl-k">extends</span> <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-c1">Component</span> <span class="pl-kos">{</span>
  <span class="pl-k">static</span> <span class="pl-c1">renderTypes</span> <span class="pl-c1">=</span> <span class="pl-kos">[</span><span class="pl-v">Button</span><span class="pl-kos">]</span><span class="pl-kos">;</span>

  <span class="pl-en">render</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-c1">&lt;</span><span class="pl-ent">Button</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function Foo({ yes }): React.Element&lt;Bar | 'div'&gt; {
  return yes ? &lt;Bar /&gt; : &lt;div /&gt;;
}

class Bar extends React.Component {
  render(): React.Element&lt;Button&gt; {
    return &lt;Button /&gt;;
  }
}"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-v">Foo</span><span class="pl-kos">(</span><span class="pl-kos">{</span> yes <span class="pl-kos">}</span><span class="pl-kos">)</span>: <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-v">Element</span><span class="pl-c1">&lt;</span><span class="pl-v">Bar</span> <span class="pl-c1">|</span> <span class="pl-s">'div'</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-s1">return</span> <span class="pl-s1">yes</span> ? <span class="pl-c1">&lt;</span><span class="pl-ent">Bar</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span> : <span class="pl-c1">&lt;</span><span class="pl-ent">div</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">class</span> <span class="pl-v">Bar</span> <span class="pl-k">extends</span> <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-c1">Component</span> <span class="pl-kos">{</span>
  <span class="pl-c1">render</span><span class="pl-kos">(</span><span class="pl-kos">)</span>: <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-v">Element</span><span class="pl-c1">&lt;</span><span class="pl-ent">Button</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-s1">return</span> <span class="pl-c1">&lt;</span><span class="pl-v">Button</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Inside <a class="user-mention notranslate" data-hovercard-type="organization" data-hovercard-url="/orgs/airbnb/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/airbnb">@airbnb</a>, we have lots of use cases where we have container components in a separate package - say, a <code class="notranslate">&lt;ButtonRow&gt;</code>, and we have intentionally restrictive propTypes on its <code class="notranslate">children</code> prop, to only allow a <code class="notranslate">Button</code> (also in the same package). However, in an app that consumes this component library package, a dev may want to create a <code class="notranslate">&lt;SpecialProductButton /&gt;</code> that in turn renders a <code class="notranslate">&lt;Button&gt;</code> - however, they're unable to pass it into <code class="notranslate">ButtonRow</code> (our propType warnings fail tests), even though conceptually it should be permitted.</p>
<p dir="auto">Having <code class="notranslate">.renderTypes</code> would allow us to widen our <code class="notranslate">children</code> propType to allow for either a <code class="notranslate">&lt;Button&gt;</code>, or <em>anything that renders a <code class="notranslate">&lt;Button&gt;</code></em>, which helps us maintain separation of concerns (the package doesn't have to know about <code class="notranslate">&lt;SpecialProductButton&gt;</code> to accept it) as well as maintain strictness (the package doesn't have to allow any wacky element inside <code class="notranslate">&lt;ButtonRow&gt;</code>).</p>
<p dir="auto">I imagine the implementation to be:</p>
<ol dir="auto">
<li>when render() is called or an SFC is invoked, (in async rendering, it'd be when the component resolves, i suppose)</li>
<li>in development only and if <code class="notranslate">.renderTypes</code> exists on the component</li>
<li>evaluate the equivalent of <a href="https://www.npmjs.com/package/airbnb-prop-types" rel="nofollow"><code class="notranslate">elementType</code></a><code class="notranslate">(...Component.renderTypes)({ children: renderedValue }, 'children', ...)</code>,</li>
<li>just like propTypes, log the error if one is returned</li>
</ol>
<p dir="auto">(cc <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/spicyj/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/spicyj">@spicyj</a>)</p>
<p dir="auto"><em>feature</em></p>
<blockquote>
<p dir="auto">Warning: A component is <code class="notranslate">contentEditable</code> and contains <code class="notranslate">children</code> managed by React. It is now your responsibility to guarantee that none of those nodes are unexpectedly modified or duplicated. This is probably not intentional.</p>
</blockquote>
<p dir="auto">It would help heaps if I would know <em>which</em> component is causing this.</p>