[React Typescript] Fixing forwardRef's Type

发布时间 2023-08-29 14:46:21作者: Zhentiw

Fix forwardRef globally

To jump ahead to the solution, uncommenting the following code from Stefan Baumgartner will globally override the value of forwardRef:

declare module "react" {
	function forwardRef<T, P = {}>(
		render: (props: P, ref: React.Ref<T>) => React.ReactNode
	): (props: P & React.RefAttributes<T>) => React.ReactNode;
}

This is a good snippet to have on hand when using forwardRef in your TypeScript projects, but there are some tradeoffs, though.

With the above solution, when we go to use ForwardReffedTable, we no longer have access to defaultProps and some of React's other properties even though we do have proper inference for the generic component.

 

Fix forwardRef locally

import { ForwardedRef, forwardRef, useRef } from "react";
import { Equal, Expect } from "../helpers/type-utils";

function fixedForwardRef<T, P = {}>(
  render: (props: P, ref: React.Ref<T>) => React.ReactNode,
): (props: P & React.RefAttributes<T>) => React.ReactNode {
  return forwardRef(render) as any;
}

type Props<T> = {
  data: T[];
  renderRow: (item: T) => React.ReactNode;
};

export const Table = <T,>(
  props: Props<T>,
  ref: ForwardedRef<HTMLTableElement>,
) => {
  return <table ref={ref} />;
};

const ForwardReffedTable = fixedForwardRef(Table);

const Parent = () => {
  const tableRef = useRef<HTMLTableElement>(null);
  const wrongRef = useRef<HTMLDivElement>(null);
  return (
    <>
      <ForwardReffedTable
        ref={tableRef}
        data={["123"]}
        renderRow={(row) => {
          type test = Expect<Equal<typeof row, string>>;
          return <div>123</div>;
        }}
      />
      <ForwardReffedTable
        // @ts-expect-error
        ref={wrongRef}
        data={["123"]}
        renderRow={(row) => {
          return <div>123</div>;
        }}
      />
    </>
  );
};