forwardRef 的泛型错误:类型“IntrinsicAttributes”上不存在属性“ref”

IT技术 reactjs typescript
2021-05-06 09:37:10

将 forwardRef 与泛型一起使用时,我得到Property 'children' does not exist on type 'IntrinsicAttributes'Property 'ref' does not exist on type 'IntrinsicAttributes'

https://codesandbox.io/s/react-typescript-0dt6d?fontsize=14

上面 CodeSandbox 链接中的相关代码复制到这里:

interface SimpleProps<T extends string>
  extends React.HTMLProps<HTMLButtonElement> {
  random: T;
}

interface Props {
  ref?: React.RefObject<HTMLButtonElement>;
  children: React.ReactNode;
}

function WithGenericsButton<T extends string>() {
  return React.forwardRef<HTMLButtonElement, Props & SimpleProps<T>>(
    ({ children, ...otherProps }, ref) => (
      <button ref={ref} className="FancyButton" {...otherProps}>
        {children}
      </button>
    )
  );
}

() => (
  <WithGenericsButton<string> ref={ref} color="green">
    Click me! // Errors: Property 'children' does not exist on type 'IntrinsicAttributes'
  </WithGenericsButton>
)

这里建议了一个潜在的解决方案,但不确定如何在这种情况下实施:https : //github.com/microsoft/TypeScript/pull/30215 (从https://stackoverflow.com/a/51898192/9973558找到

4个回答

所以这里的主要问题是你React.forwardRef在渲染中返回的结果,这不是渲染函数的有效返回类型。您需要将 forwardRef 结果定义为它自己的组件,然后将其呈现在您的 WithGenericsButton 高阶组件中,如下所示:

import * as React from "react";

interface SimpleProps<T extends string> {
  random: T;
}

interface Props {
  children: React.ReactNode;
  color: string;
}

function WithGenericsButton<T extends string>(
  props: Props & SimpleProps<T> & { ref: React.Ref<HTMLButtonElement> }
) {
  type CombinedProps = Props & SimpleProps<T>;
  const Button = React.forwardRef<HTMLButtonElement, CombinedProps>(
    ({ children, ...otherProps }, ref) => (
      <button ref={ref} className="FancyButton" {...otherProps}>
        {children}
      </button>
    )
  );
  return <Button {...props} />;
}

const App: React.FC = () => {
  const ref = React.useRef<HTMLButtonElement>(null);
  return (
    <WithGenericsButton<string> ref={ref} color="green" random="foo">
      Click me!
    </WithGenericsButton>
  );
};

如果你把它放在沙箱或操场上,你会看到props现在输入正确,包括一个randompropsT

您遇到的问题是由于此功能:

function WithGenericsButton<T extends string>() {
  return React.forwardRef<HTMLButtonElement, Props & SimpleProps<T>>(
    ({ children, ...otherProps }, ref) => (
      <button ref={ref} className="FancyButton" {...otherProps}>
        {children}
      </button>
    )
  );
}

WithGenericsButton不是组件。它是一个返回组件的js函数。TS 基本上是在告诉您:嘿组件WithGenericsButton(因为您将它用作一个组件)没有调用 prop children,它是正确的,它没有。

在您的情况下,要获得可以渲染的组件,您需要执行以下操作: const StringButton = WithGenericsButton<string>();

我找到了另一种解决问题的好方法。像这样的东西,

export interface Props = {
   ...yourPropsHere;
};

export interface CompoundedComponent extends React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLInputElement>> {
   yourStaticFunctionOrSomethingLikeThat: () => void;
}

const Component = React.forwardRef<HTMLInputElement, Props>((props, ref) => (
    <input ref={ref} {...props} />
)) as CompoundedComponent;

Component.yourStaticFunctionOrSomethingLikeThat = () => {};

一个对我有用的方便的替代方案,(根本没有打字专家)

const ReusableComponent = React.forwardRef((props: { [key: string]: unknown }, ref) => {
  const { ref, children, ...moreProps } = props
  return (
    <Something ref={ref} {...moreProps}>
      {children}
    </Something>
  )
})
export default ReusableComponent

发现[key: string]: unknown在无法知道您收到什么props时使用起来很方便