【问题标题】:Using a forwardRef component with children in TypeScript在 TypeScript 中使用带有子项的 forwardRef 组件
【发布时间】:2019-07-06 08:22:33
【问题描述】:

使用 @types/react 16.8.2 和 TypeScript 3.3.1。

我直接从React documentation 中提取了这个前向引用示例并添加了几个类型参数:

const FancyButton = React.forwardRef<HTMLButtonElement>((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef<HTMLButtonElement>();
<FancyButton ref={ref}>Click me!</FancyButton>;

FancyButton 下的最后一行出现以下错误:

类型“{ children: string; ref: RefObject&lt;HTMLButtonElement&gt;; }”不是 可分配给类型“IntrinsicAttributes &amp; RefAttributes&lt;HTMLButtonElement&gt;”。属性“children”不 存在于类型'IntrinsicAttributes &amp; RefAttributes&lt;HTMLButtonElement&gt;'.ts(2322)

React.forwardRef 的返回值的类型定义似乎是错误的,没有正确合并 children 属性。如果我让&lt;FancyButton&gt; 自动关闭,错误就会消失。缺少此错误的搜索结果让我相信我遗漏了一些明显的东西。

【问题讨论】:

    标签: reactjs typescript jsx tsx


    【解决方案1】:

    aMarCruz 和 euvs 给出的答案都行得通,但它们对消费者有点撒谎。他们说他们接受所有 HTMLButtonElement 道具,但他们忽略它们而不是将它们转发给按钮。如果您只是想正确合并 children 道具,那么您可能想要使用 React.PropsWithChildren 代替:

    import React from 'react';
    
    interface FancyButtonProps {
        fooBar?: string; // my custom prop
    }
    
    const FancyButton = React.forwardRef<HTMLButtonElement, React.PropsWithChildren<FancyButtonProps>>((props, ref) => (
        <button type="button" ref={ref} className="fancy-button">
            {props.children}
            {props.fooBar}
        </button>
    ));
    
    FancyButton.displayName = 'FancyButton';
    

    或显式添加 children 属性:

    interface FancyButtonProps {
        children?: React.ReactNode;
        fooBar?: string; // my custom prop
    }
    
    const FancyButton = React.forwardRef<HTMLButtonElement, FancyButtonProps>((props, ref) => (
        <button type="button" ref={ref} className="fancy-button">
            {props.children}
            {props.fooBar}
        </button>
    ));
    
    FancyButton.displayName = 'FancyButton';
    

    或者如果你真的想要接受所有的按钮道具并转发它们(例如让消费者选择按钮类型=“提交”),那么你可能想要使用rest/spread:

    import React from 'react';
    
    interface FancyButtonProps extends React.ComponentPropsWithoutRef<'button'> {
        fooBar?: string; // my custom prop
    }
    
    const FancyButton = React.forwardRef<HTMLButtonElement, FancyButtonProps>(
        ({ children, className = '', fooBar, ...buttonProps }, ref) => (
            <button {...buttonProps} className={`fancy-button ${className}`} ref={ref}>
                {children}
                {fooBar}
            </button>
        ),
    );
    
    FancyButton.displayName = 'FancyButton';
    

    【讨论】:

    • 谢谢!非常有帮助和疲惫的答案!
    • ...buttonProps }: FancyButtonProps, ref)
    • 这应该是正确的答案。 PropsWithChildren 正是我们所需要的。
    【解决方案2】:

    aMarCruz 给出的答案效果很好。但是,如果您还需要将自定义 props 传递给 FancyButton,可以这样做。

    interface FancyButtonProps extends React.ComponentPropsWithoutRef<'button'> {
        fooBar?: string; // my custom prop
    }
    
    const FancyButton = React.forwardRef<HTMLButtonElement, FancyButtonProps>((props, ref) => (
        <button type="button" ref={ref} className="FancyButton">
            {props.children}
            {props.fooBar}
        </button>
    ));
    
    
    /// Use later
    
    // You can now get a ref directly to the DOM button:
    const ref = React.createRef<HTMLButtonElement>()
    
    <FancyButton ref={ref} fooBar="someValue">Click me!</FancyButton>
    
    

    只需在此处添加即可完成。

    【讨论】:

      【解决方案3】:

      trevorsg,你需要传递按钮属性:

      import * as React from 'react'
      
      type ButtonProps = React.HTMLProps<HTMLButtonElement>
      
      const FancyButton = React.forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => (
        <button type="button" ref={ref} className="FancyButton">
          {props.children}
        </button>
      ))
      
      // You can now get a ref directly to the DOM button:
      const ref = React.createRef<HTMLButtonElement>()
      
      <FancyButton ref={ref}>Click me!</FancyButton>
      

      添加:

      在最新版本的 TS 和 @types/react 中,您还可以使用 React.ComponentPropsWithoutRef&lt;'button'&gt; 代替 React.HTMLProps&lt;HTMLButtonElement&gt;

      【讨论】:

      • 哇,谢谢,React.ComponentPropsWithoutRef 工作得很好。你是怎么发现它存在的?在@types/react 中,IntrinsicElements.button 的类型定义为 React.DetailedHTMLProps, HTMLButtonElement>。我正在拔头发试图与那种类型一起工作
      • 韦斯顿,这是逻辑上的,试图找到一个定义来替换 react-bootstrap 类型中的“ref”。
      • 我讨厌 TS 这样的事情
      猜你喜欢
      • 2021-01-03
      • 2019-01-23
      • 1970-01-01
      • 2019-06-07
      • 2021-08-25
      • 2021-12-14
      • 2021-07-11
      • 2017-04-06
      • 1970-01-01
      相关资源
      最近更新 更多