8

I'm getting a ts error when using forwardRef

// [ts] Property 'forwardRef' does not exist on type 'typeof React'.
const MyComponent = React.forwardRef((props: Props, ref: any) => ...

In React Native the parent component is throwing this error:

Invariant Violation: Element type is invalid: expected a string (for build-in components) or a class/function (for composite components) but got: object

Any idea on how to solve it?

1 Answer 1

12

According to the definitions:

function forwardRef<T, P = {}>(Component: RefForwardingComponent<T, P>): ComponentType<P & ClassAttributes<T>>;
interface RefForwardingComponent<T, P = {}> {
    (props: P & { children?: ReactNode }, ref?: Ref<T>): ReactElement<any> | null;
    propTypes?: ValidationMap<P>;
    contextTypes?: ValidationMap<any>;
    defaultProps?: Partial<P>;
    displayName?: string;
}

ref is an optional argument, try the following:

Inside a class create a ref object with a type parameter equal to your desired target (in my case div but View also works in react-native)

private divRef: React.RefObject<div> = React.createRef();

In the interface that represents the props for the forwarded component expose it as an optional property

interface Props {
  ref?: React.RefObject<div>;
}

Declare the forwarded component with the type React.ComponentType

const ComponentWithForwardedRef: React.ComponentType<Props> = 
  React.forwardRef((props: Props, ref?: React.Ref<div>) => (
    <div ref={ref}>{props.message}</div>
  ));

When an instance of the component with the forwarded ref is created send the created ref object as a prop

<ComponentWithForwardedRef ref={this.divRef} />

All in one:

import * as React from "react";
import { render } from "react-dom";

interface Props {
  message: string;
  ref?: React.RefObject<div>;
}

const ComponentWithForwardedRef: React.ComponentType<Props> = 
  React.forwardRef((props: Props, ref?: React.Ref<div>) => (
    <div ref={ref}>{props.message}</div>
  ));

class App extends React.Component<Props> {
  private divRef: React.RefObject<div> = React.createRef();

  public componentDidMount() {
    const div = this.divRef.current;
    // check the console!
    console.log(div);
  }

  public render() {
    return (
      <ComponentWithForwardedRef ref={this.divRef} {...this.props} />
    )
  }
}

render(<App message="hello world" />, document.getElementById("root"));

Link for posterity: https://codesandbox.io/s/6v152q394k

Dependencies (reference purposes)

"@types/react": "^16.3.11",
"@types/react-native": "^0.55.19",
"react-native": "0.55.2",
"typescript": "^2.8.1"
Sign up to request clarification or add additional context in comments.

1 Comment

In my case it was React.Ref<HTMLDivElement>. I'm also no sture why you're listing ref in the interface Props. At least for me this was not necessary and doesn't make sense since it's not part of props: Props

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.