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].
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.
Most helpful comment
My apologies, it's expected we type our
Refwith a string literal, rather than an actual runtime type e.g.We should use
React.Ref<'div'>instead ofReact.Ref<HTMLDivElement>.This seems a little odd to me, but works well enough once you realize.