19

Since React 16.3 it is possible to use React.createRef() to access a DOM element. I am also using Flow in my project, but the documentation still uses the old way.

The below code unfortunately fails:

/* @flow */
import * as React from 'react';

export class TestComponent extends React.Component<{}> {
  myRef: React.Ref<HTMLDivElement>

  constructor(props: any) {
    super(props)
    this.myRef = React.createRef()
  }

  render() {
    return (
      <div ref={this.myRef} />
    )
  }
}

with the following error:

Cannot instantiate `Ref` because in type argument `ElementType`:
 - Either a callable signature is missing in `HTMLDivElement` [1] but exists in
   `React.StatelessFunctionalComponent` [2].
 - Or `HTMLDivElement` [1] is incompatible with statics of `React.Component` [3].

How do I type it correctly?

skyboyer
  • 15,149
  • 4
  • 41
  • 56
Zardoz
  • 14,339
  • 21
  • 79
  • 126

4 Answers4

24

Looking at the flow type definition for React.createRef():

declare export function createRef<ElementType: React$ElementType>(
): {current: null | React$ElementRef<ElementType>};

I was able to do something like this:

/* @flow */
import * as React from 'react';

export class TestComponent extends React.Component<{}> {
  myRef: { current: null | HTMLDivElement }

  constructor(props: any) {
    super(props)
    this.myRef = React.createRef()
  }

  render() {
    return (
      <div ref={this.myRef} />
    )
  }
}
allienx
  • 867
  • 5
  • 9
2

There is a related github issue.

If it's not fixed yet you can type it yourself:

type RefObject = {|
  current: any,
|};

This is how it is typed internally in react library type definitions.

Tomasz Mularczyk
  • 27,156
  • 17
  • 99
  • 146
  • When trying to use the self defined RefObject I get the error `Cannot assign React.createRef() to this.myRef because inexact object type [1] is incompatible with exact RefObject [2].` Any idea? (I am quite new to flow). – Zardoz Apr 28 '18 at 12:07
  • @Zardoz try like this: `type RefObject = { current: any };` – Tomasz Mularczyk Apr 28 '18 at 12:14
1

If you are using "class properties", you may createRef() in the following way:

// @flow
import * as React from 'react';

export class TestComponent extends React.Component<{}> {
  myRef = React.createRef<HTMLElement>();

  render() {
    return (
      <div ref={this.myRef} />
    )
  }
}
jmarceli
  • 15,970
  • 5
  • 57
  • 57
0

In my case I was using formik reference

// @flow
import React from 'react';
import { Formik } from "formik"


export class TestComponent extends React.Component<Props> {
   formikRef = React.createRef<Formik>();

  render() {
     return (
         <Formik 
            ...,
            ref={this.formikRef}
         />
     )
  }
}
Umar Asghar
  • 2,332
  • 1
  • 21
  • 21