<p dir="auto">If you know how to fix the issue, make a pull request instead.</p>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I tried using the <code class="notranslate">@types/xxxx</code> package and had problems.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I tried using the latest stable version of tsc. <a href="https://www.npmjs.com/package/typescript" rel="nofollow">https://www.npmjs.com/package/typescript</a></li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I have a question that is inappropriate for <a href="https://stackoverflow.com/" rel="nofollow">StackOverflow</a>.  (Please ask any appropriate questions there).</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> <a href="https://github.com/blog/821-mention-somebody-they-re-notified">Mention</a> the authors (see <code class="notranslate">Definitions by:</code> in <code class="notranslate">index.d.ts</code>) so they can respond.
<ul dir="auto">
<li>Authors: <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/johnnyreilly/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/johnnyreilly">@johnnyreilly</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/bbenezech/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/bbenezech">@bbenezech</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/pzavolinsky/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/pzavolinsky">@pzavolinsky</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/digiguru/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/digiguru">@digiguru</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/ericanderson/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/ericanderson">@ericanderson</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/DovydasNavickas/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/DovydasNavickas">@DovydasNavickas</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/theruther4d/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/theruther4d">@theruther4d</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/guilhermehubner/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/guilhermehubner">@guilhermehubner</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/ferdaber/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/ferdaber">@ferdaber</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/jrakotoharisoa/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/jrakotoharisoa">@jrakotoharisoa</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/pascaloliv/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/pascaloliv">@pascaloliv</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/Hotell/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/Hotell">@Hotell</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/franklixuefei/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/franklixuefei">@franklixuefei</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/Jessidhia/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/Jessidhia">@Jessidhia</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/saranshkataria/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/saranshkataria">@saranshkataria</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/lukyth/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/lukyth">@lukyth</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/eps1lon/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/eps1lon">@eps1lon</a></li>
</ul>
</li>
</ul>
<p dir="auto">Hello! I am facing an issue when trying to type the <code class="notranslate">ref</code> property of a custom component.</p>
<p dir="auto">This is the setup I have:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// someFile.TS
// Due to some weird Webpack rules and the app's architecture I have this interface in a file which
// cannot import the TableComponent from its TableComponent.tsx file.
// Therefore, I am trying to emulate the end result of the React.createElement function call
interface ITableComponent {
  tableProps: IlDataTableProps; // This is the only property I need to access
}

interface ITableComponentProps {
  ref: React.RefObject&lt;ITableComponent&gt;
}

// someOtherFile.TSX
class TableComponent extends React.Component&lt;ITableComponentProps&gt; implements ITableComponent {}

// somewhereInTheApp.TSX
class SomeComponent extends ... {
  tableRef = React.createRef&lt;ITableComponent&gt;();
  render () {
    return &lt;TableComponent ref={this.tableRef}/&gt;; // *Read below
  }
}"><pre class="notranslate"><span class="pl-c">// someFile.TS</span>
<span class="pl-c">// Due to some weird Webpack rules and the app's architecture I have this interface in a file which</span>
<span class="pl-c">// cannot import the TableComponent from its TableComponent.tsx file.</span>
<span class="pl-c">// Therefore, I am trying to emulate the end result of the React.createElement function call</span>
<span class="pl-s1">interface</span> <span class="pl-v">ITableComponent</span> <span class="pl-kos">{</span>
  tableProps: <span class="pl-v">IlDataTableProps</span><span class="pl-kos">;</span> <span class="pl-c">// This is the only property I need to access</span>
<span class="pl-kos">}</span>

<span class="pl-s1">interface</span> <span class="pl-v">ITableComponentProps</span> <span class="pl-kos">{</span>
  ref: <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-c1">RefObject</span><span class="pl-c1">&lt;</span><span class="pl-v">ITableComponent</span><span class="pl-c1">&gt;</span>
<span class="pl-kos">}</span>

<span class="pl-c">// someOtherFile.TSX</span>
<span class="pl-k">class</span> <span class="pl-v">TableComponent</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-c1">&lt;</span><span class="pl-v">ITableComponentProps</span><span class="pl-c1">&gt;</span> <span class="pl-s1">implements</span> <span class="pl-v">ITableComponent</span> <span class="pl-kos">{</span><span class="pl-kos">}</span>

<span class="pl-c">// somewhereInTheApp.TSX</span>
<span class="pl-k">class</span> <span class="pl-v">SomeComponent</span> <span class="pl-k">extends</span> ... <span class="pl-kos">{</span>
  tableRef <span class="pl-c1">=</span> <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-c1">createRef</span><span class="pl-c1">&lt;</span><span class="pl-v">ITableComponent</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</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>
    return<span class="pl-kos"></span> <span class="pl-c1">&lt;</span><span class="pl-v">TableComponent</span> <span class="pl-s1">ref</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">this</span><span class="pl-kos">.</span><span class="pl-c1">tableRef</span><span class="pl-kos">}</span><span class="pl-c1">/</span>&gt;; <span class="pl-c">// *Read below</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">*Over here I get the following error:<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/24717857/65044496-ab471f00-d965-11e9-916f-69dc1dde010c.png"><img src="https://user-images.githubusercontent.com/24717857/65044496-ab471f00-d965-11e9-916f-69dc1dde010c.png" alt="image" style="max-width: 100%;"></a></p>
<p dir="auto">Looking through the type definition of ref I came across this line:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="    type Ref&lt;T&gt; = { bivarianceHack(instance: T | null): void }[&quot;bivarianceHack&quot;] | RefObject&lt;T&gt; | null;"><pre class="notranslate">    <span class="pl-s1">type</span> <span class="pl-v">Ref</span><span class="pl-c1">&lt;</span><span class="pl-v">T</span><span class="pl-c1">&gt;</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span> <span class="pl-c1">bivarianceHack</span><span class="pl-kos">(</span><span class="pl-s1">instance</span>: <span class="pl-v">T</span> <span class="pl-c1">|</span> <span class="pl-c1">null</span><span class="pl-kos">)</span>: <span class="pl-k">void</span> <span class="pl-kos">}</span><span class="pl-kos">[</span><span class="pl-s">"bivarianceHack"</span><span class="pl-kos">]</span> <span class="pl-c1">|</span> <span class="pl-v">RefObject</span><span class="pl-c1">&lt;</span><span class="pl-v">T</span><span class="pl-c1">&gt;</span> <span class="pl-c1">|</span> <span class="pl-c1">null</span><span class="pl-kos"></span><span class="pl-kos">;</span></pre></div>
<p dir="auto">and this one:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="    function createRef&lt;T&gt;(): RefObject&lt;T&gt;;"><pre class="notranslate"><code class="notranslate">    function createRef&lt;T&gt;(): RefObject&lt;T&gt;;
</code></pre></div>
<p dir="auto">Seeing as <code class="notranslate">createRef</code> returns a T, in my case that should be <code class="notranslate">ITableComponent</code>. And the ref type also has an option of <code class="notranslate">RefObject&lt;T&gt;</code>. However, as the error shows, it looks for something which is <code class="notranslate">(string &amp; RefObject&lt;T&gt;)</code>. I don't understand where that <code class="notranslate">string &amp;</code> is coming for and I also cannot find an explanation why is it needed. To my understanding, the <code class="notranslate">string</code> refs were the first implementation and were deprecated. So why does that type need to interfere with the <code class="notranslate">React.RefObject&lt;T&gt;</code>. Or, if it must interfere, why is it that the <code class="notranslate">React.createRef</code> function is not returning that <code class="notranslate">string &amp; RefObject&lt;T&gt;</code> definition? If I change the definition to that in the <code class="notranslate">@types/react/index.d.ts</code> file everything works as it should.</p>
<p dir="auto"><strong>TypeScript Version:</strong>  3.4.0-dev.201xxxxx</p>

<p dir="auto"><strong>Search Terms:</strong><br>
react, ref</p>
<p dir="auto"><strong>Code</strong></p>
<div class="highlight highlight-source-tsx notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="const genericRef = React.createRef&lt;Element&gt;();
const inputRef = React.createRef&lt;HTMLInputElement&gt;();

// throws, undesired: HTMLInputElement extends Element
&lt;input ref={genericRef} /&gt;;
// works, desired
React.createElement(&quot;input&quot;, { ref: genericRef });
// works, desired
&lt;input ref={inputRef} /&gt;;
// works, desired
React.createElement(&quot;input&quot;, { ref: inputRef });

// throws, undesired: same issue as #1 other motivation
const ElementComponent = React.forwardRef&lt;Element&gt;((_, ref) =&gt; (
  &lt;div ref={ref} /&gt;
));

// works, desired
&lt;ElementComponent ref={genericRef} /&gt;;
// works, desired
React.createElement(ElementComponent, { ref: genericRef });
// works, undesired: inputRef.current.value would be undefined at runtime
&lt;ElementComponent ref={inputRef} /&gt;;
// works, undesired: see jsx example
React.createElement(ElementComponent, { ref: inputRef });"><pre class="notranslate"><span class="pl-k">const</span> <span class="pl-s1">genericRef</span> <span class="pl-c1">=</span> <span class="pl-smi">React</span><span class="pl-kos">.</span><span class="pl-en">createRef</span><span class="pl-kos">&lt;</span><span class="pl-smi">Element</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">const</span> <span class="pl-s1">inputRef</span> <span class="pl-c1">=</span> <span class="pl-smi">React</span><span class="pl-kos">.</span><span class="pl-en">createRef</span><span class="pl-kos">&lt;</span><span class="pl-smi">HTMLInputElement</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-c">// throws, undesired: HTMLInputElement extends Element</span>
<span class="pl-c1">&lt;</span><span class="pl-ent">input</span> <span class="pl-c1">ref</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">genericRef</span><span class="pl-kos">}</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
<span class="pl-c">// works, desired</span>
<span class="pl-smi">React</span><span class="pl-kos">.</span><span class="pl-en">createElement</span><span class="pl-kos">(</span><span class="pl-s">"input"</span><span class="pl-kos">,</span> <span class="pl-kos">{</span> <span class="pl-c1">ref</span>: <span class="pl-s1">genericRef</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">// works, desired</span>
<span class="pl-c1">&lt;</span><span class="pl-ent">input</span> <span class="pl-c1">ref</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">inputRef</span><span class="pl-kos">}</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
<span class="pl-c">// works, desired</span>
<span class="pl-smi">React</span><span class="pl-kos">.</span><span class="pl-en">createElement</span><span class="pl-kos">(</span><span class="pl-s">"input"</span><span class="pl-kos">,</span> <span class="pl-kos">{</span> <span class="pl-c1">ref</span>: <span class="pl-s1">inputRef</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-c">// throws, undesired: same issue as #1 other motivation</span>
<span class="pl-k">const</span> <span class="pl-smi">ElementComponent</span> <span class="pl-c1">=</span> <span class="pl-smi">React</span><span class="pl-kos">.</span><span class="pl-en">forwardRef</span><span class="pl-kos">&lt;</span><span class="pl-smi">Element</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-s1">_</span><span class="pl-kos">,</span> <span class="pl-s1">ref</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">(</span>
  <span class="pl-c1">&lt;</span><span class="pl-ent">div</span> <span class="pl-c1">ref</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">ref</span><span class="pl-kos">}</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>

<span class="pl-c">// works, desired</span>
<span class="pl-c1">&lt;</span><span class="pl-smi">ElementComponent</span> <span class="pl-c1">ref</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">genericRef</span><span class="pl-kos">}</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
<span class="pl-c">// works, desired</span>
<span class="pl-smi">React</span><span class="pl-kos">.</span><span class="pl-en">createElement</span><span class="pl-kos">(</span><span class="pl-smi">ElementComponent</span><span class="pl-kos">,</span> <span class="pl-kos">{</span> <span class="pl-c1">ref</span>: <span class="pl-s1">genericRef</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">// works, undesired: inputRef.current.value would be undefined at runtime</span>
<span class="pl-c1">&lt;</span><span class="pl-smi">ElementComponent</span> <span class="pl-c1">ref</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">inputRef</span><span class="pl-kos">}</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
<span class="pl-c">// works, undesired: see jsx example</span>
<span class="pl-smi">React</span><span class="pl-kos">.</span><span class="pl-en">createElement</span><span class="pl-kos">(</span><span class="pl-smi">ElementComponent</span><span class="pl-kos">,</span> <span class="pl-kos">{</span> <span class="pl-c1">ref</span>: <span class="pl-s1">inputRef</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto"><strong>Expected behavior:</strong></p>
<ul dir="auto">
<li>same behavior between JSX and React.createElement</li>
<li>undesired behavior gets fixed</li>
</ul>
<p dir="auto"><strong>Actual behavior:</strong></p>
<ul dir="auto">
<li>different behavior with and without JSX</li>
<li>2 undesired errors, 1 undesired pass</li>
</ul>
<p dir="auto"><strong>Playground Link:</strong> <br>
<a href="https://github.com/eps1lon/typescript-react-ref-issue">https://github.com/eps1lon/typescript-react-ref-issue</a></p>
<p dir="auto"><strong>Related Issues:</strong> <br>
<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="230650942" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/16019" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/16019/hovercard" href="https://github.com/microsoft/TypeScript/issues/16019">#16019</a></p>
<p dir="auto">I suppose the main issue is how react handles refs. Since react never reads the <code class="notranslate">current</code> value it's perfectly fine to pass a less specific type to the <code class="notranslate">ref</code> attribute. I'm not sure if we can express this behavior with types, it is a current limitation that should be fixed or if this is working as intended.</p>