Flow: Cannot assign React.createRef() to this.[property] because inexact object type [1] is incompatible with exact RefObject

Created on 30 May 2018  路  13Comments  路  Source: facebook/flow

I understand that Flow doesn't presently support React.createRef() type definitions.

From React's source code, I found these:

export function createRef(): RefObject {
  const refObject = {
    current: null,
  };
  if (__DEV__) {
    Object.seal(refObject);
  }
  return refObject;
}
export type RefObject = {|
  current: any,
|};

I tried using this snippet in my code, but I get an error instead:

Cannot assign React.createRef() to this.[property] because inexact object type [1] is incompatible with exact RefObject [2].

Library definitions

Most helpful comment

My apologies, it's expected we type our Ref with a string literal, rather than an actual runtime type e.g.

We should use React.Ref<'div'> instead of React.Ref<HTMLDivElement>.

This seems a little odd to me, but works well enough once you realize.

All 13 comments

I've updated to the latest React and Flow versions, still getting these though!

Could you please reproduce it on flow.org/try

I'm not sure how I can introduce React into the Try Flow environment, but I found a solution:

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

to:

export type RefObject = { current: any, };

By removing the pipelines/vertical bars, I no longer get the inexact object type is incompatible with exact RefObject error, although I don't quite understand why this happens, considering I copied and pasted the type definition.

Did you read the end of that issue? createRef api is supported for a few last versions.
https://github.com/facebook/flow/blob/master/lib/react.js#L219

@fterh you can write import React from 'react' on Try Flow environment.

@TrySound I did, which was why I mentioned that I have updated to the latest versions and confirmed that the error still occurs.

However, that was using my original code - I didn't see any updates in the Flow documentation - so thanks for linking me to the source code, I'll have a look when I can and see if I can figure it out.

It would be nice if the flow documentation for refs was updated. I tried typing a ref using the createRef API today, but couldn't get it to work.

I tried something like this:

type Ref = { current: null | HTMLElement };

export default class SomeClass extends React.Component<Props> {
    someRef: Ref;

    constructor(props: Props) {
        super(props);
        this.someRef = React.createRef();
    }

    render() {
        return (
            <Component ref={this.someRef} />
        );
    }
}

This gives me an error:
Cannot create Component element because a callable signature is missing in Ref [1] but exists in function type [2] in property ref.

Where [1] refers to the Ref type and [2] refers to the creatRef function type definition in flow.

So, what did I do wrong / should I do to fix this?

@im-martijn Documenting every type definition is wasting of resources. Read actual definitions. They are quite clean and always in current state.
https://github.com/facebook/flow/blob/master/lib/react.js#L189

Yeah, I did look at that, but didn't get it completely. New to flow / typing in general.

declare type React$Ref<ElementType: React$ElementType> =
  | {current: React$ElementRef<ElementType> | null}
  | ((React$ElementRef<ElementType> | null) => mixed)
  | string;

This is how I decided to use: { current: null | HTMLElement }. I guess I'm not sure how to interpret React$ElementRef<ElementType>.

React$Ref is global alias of

import * as React from 'react';
var a: React.Ref

same true for all react types.

Ah, great, thanks. I now have:

import * as React from 'react';
type Ref = { current: React.ElementRef<any> | null };

...and that seems to work.

But still: is this not outdated now? https://flow.org/en/docs/react/refs/

The current flow type for Ref and createRef are incorrect, the type parameter is "specialized" as:

ElementType: React$ElementType

where we have React$ElementType:

declare type React$ElementType =
  | string
  | React$StatelessFunctionalComponent<any>
  | Class<React$Component<any, any>>;

This means Flow does not allow us to specify references to DOM elements (i.e. HTMLElement). This is incorrect as references to DOM elements is documented behavior, https://reactjs.org/docs/refs-and-the-dom.html

My apologies, it's expected we type our Ref with a string literal, rather than an actual runtime type e.g.

We should use React.Ref<'div'> instead of React.Ref<HTMLDivElement>.

This seems a little odd to me, but works well enough once you realize.

Was this page helpful?
0 / 5 - 0 ratings