Definitelytyped: [@types/react-redux] connect + React.forwardRef: wrong ref attribute type

Created on 22 May 2019  路  6Comments  路  Source: DefinitelyTyped/DefinitelyTyped

  • [x] I tried using the @types/[email protected] package and had problems.
  • [x] I tried using the latest stable version of tsc. https://www.npmjs.com/package/typescript
  • [x] I have a question that is inappropriate for StackOverflow. (Please ask any appropriate questions there).
  • [x] [Mention](https://github.com/blog/821-mention-somebody-they-re-notified) the authors (see Definitions by: in index.d.ts) so they can respond.

    • Authors: @tkqubo @kenzierocks @clayne11 @tansongyang @nicholasboll @mdibyo @kallikrein @val1984 @jrakotoharisoa @apapirovski @surgeboris @soerenbf

The type of the ref attribute after applying connect to the component that was produced by React.forwardRef is wrong.

import React from "react";
import { connect } from "react-redux";

interface Props {}

interface PropsWithForwardedRef extends Props {
    forwardedRef?: React.Ref<HTMLDivElement>;
}

function Component(props: PropsWithForwardedRef) {
    return <div ref={props.forwardedRef} />;
}

const RefForwardingComponent = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
    return <Component {...props} forwardedRef={ref} />;
});

const ConnectedRefForwardingComponent = connect(
    null,
    null,
    null,
    { forwardRef: true }
)(RefForwardingComponent);

const ref = React.createRef<HTMLDivElement>();
const jsx = <ConnectedRefForwardingComponent ref={ref} />; // should be no error
index.tsx:26:46 - error TS2322: Type 'RefObject<HTMLDivElement>' is not assignable to type '(string & ((instance: HTMLDivElement | null) => void)) | (string & RefObject<HTMLDivElement>) | (((instance: Component<Pick<Props & RefAttributes<HTMLDivElement>, "key" | "ref">, any, any> | null) => void) & ((instance: HTMLDivElement | null) => void)) | ... 4 more ... | undefined'.
  Type 'RefObject<HTMLDivElement>' is not assignable to type 'RefObject<Component<Pick<Props & RefAttributes<HTMLDivElement>, "key" | "ref">, any, any>> & RefObject<HTMLDivElement>'.
    Type 'RefObject<HTMLDivElement>' is not assignable to type 'RefObject<Component<Pick<Props & RefAttributes<HTMLDivElement>, "key" | "ref">, any, any>>'.
      Type 'HTMLDivElement' is missing the following properties from type 'Component<Pick<Props & RefAttributes<HTMLDivElement>, "key" | "ref">, any, any>': context, setState, forceUpdate, render, and 3 more.

26 const jsx = <ConnectedRefForwardingComponent ref={ref} />; // should be no error
                                                ~~~

  node_modules/@types/react/index.d.ts:97:9
    97         ref?: LegacyRef<T>;
               ~~~
    The expected type comes from property 'ref' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Pick<Props & RefAttributes<HTMLDivElement>, "key" | "ref">, any, any>> & Readonly<Pick<Props & RefAttributes<HTMLDivElement>, "key" | "ref">> & Readonly<...>'


Found 1 error.

Minimal reproducible example: https://github.com/vkrol/typescript-react-forward-ref-react-redux-connect

Most helpful comment

I'm also having this issue

All 6 comments

I'm also having this issue

I was able to work around this problem by explicitly installing an earlier version:

npm install --save @types/[email protected]

This specific example is fixed in the latest version, but there is still an issue when using useRef instead of createRef:

import React from "react";
import { connect } from "react-redux";

interface Props {}

interface PropsWithForwardedRef extends Props {
  forwardedRef?: React.Ref<HTMLDivElement>;
}

function Component(props: PropsWithForwardedRef) {
  return <div ref={props.forwardedRef} />;
}

const RefForwardingComponent = React.forwardRef<HTMLDivElement, Props>(
  (props, ref) => {
    return <Component {...props} forwardedRef={ref} />;
  }
);

const ConnectedRefForwardingComponent = connect(null, null, null, {
  forwardRef: true
})(RefForwardingComponent);

const App: React.FunctionComponent = () => {
  const ref = React.useRef<HTMLDivElement>();
  return (
    <ConnectedRefForwardingComponent ref={ref} /> // should be no error
  );
}

This specific example is fixed in the latest version

Yes, it's. Thank you!

but there is still an issue when using useRef instead of createRef

It's OK. Compare it to:

const ref = React.useRef<HTMLDivElement>();
const jsx = <div ref={ref} />;

I'm confused. Does it mean we can't use the useRef hook?

Does it mean we can't use the useRef hook?

No. In this example, you can use it this way:

const ref = React.useRef<HTMLDivElement>(null);
const jsx = <div ref={ref} />; // No error

Explanation: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/38228#issuecomment-529749802.

Was this page helpful?
0 / 5 - 0 ratings