【问题标题】:Generics error with forwardRef: Property 'ref' does not exist on type 'IntrinsicAttributes'forwardRef 的泛型错误:类型“IntrinsicAttributes”上不存在属性“ref”
【发布时间】:2020-01-05 03:02:51
【问题描述】:

将 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

【问题讨论】:

    标签: reactjs typescript


    【解决方案1】:

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

    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(因为你将它作为一个组件使用)没有名为children 的道具,没错,它没有。

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

    【讨论】:

    • 谢谢约翰尼 - 你介意告诉我如何在你的情况下将道具传递给StringButton(你可以修改我的沙盒链接)
    • 以更简单的方式,这就是问题所在,返回一个函数与一个组件,并且没有在中定义其道具
    【解决方案2】:

    所以这里的主要问题是您在渲染中返回了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 现在输入正确,包括 Trandom 属性

    【讨论】:

    • 谢谢,马特!这摆脱了我一直试图修复的IntrinsicAttributes 错误。 :D
    【解决方案3】:

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

    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 = () => {};
    

    【讨论】:

      【解决方案4】:

      对我有用的便捷替代方案,(根本不是打字稿专家)

      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 很方便。

      【讨论】:

        猜你喜欢
        • 2021-04-10
        • 2021-08-23
        • 2021-08-20
        • 2019-07-31
        • 2021-10-29
        • 2021-03-17
        • 2022-12-11
        • 2022-12-30
        • 2020-09-03
        相关资源
        最近更新 更多