在 TypeScript 中使用带有子组件的 forwardRef 组件
Using a forwardRef component with children in TypeScript
使用@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
下的最后一行收到以下错误:
Type '{ children: string; ref: RefObject<HTMLButtonElement>; }
' is not
assignable to type 'IntrinsicAttributes & RefAttributes<HTMLButtonElement>
'. Property 'children
' does not
exist on type 'IntrinsicAttributes & RefAttributes<HTMLButtonElement>
'.ts(2322)
似乎 React.forwardRef 的 return 值的类型定义是错误的,没有正确地合并到 children 属性中。如果我让 <FancyButton>
自动关闭,错误就会消失。缺少此错误的搜索结果让我相信我遗漏了一些明显的东西。
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<'button'>
代替React.HTMLProps<HTMLButtonElement>
aMarCruz 给出的答案很有效。但是,如果您还需要将自定义道具传递给 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>
只是在这里添加完成。
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';
使用@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
下的最后一行收到以下错误:
Type '
{ children: string; ref: RefObject<HTMLButtonElement>; }
' is not assignable to type 'IntrinsicAttributes & RefAttributes<HTMLButtonElement>
'. Property 'children
' does not exist on type 'IntrinsicAttributes & RefAttributes<HTMLButtonElement>
'.ts(2322)
似乎 React.forwardRef 的 return 值的类型定义是错误的,没有正确地合并到 children 属性中。如果我让 <FancyButton>
自动关闭,错误就会消失。缺少此错误的搜索结果让我相信我遗漏了一些明显的东西。
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<'button'>
代替React.HTMLProps<HTMLButtonElement>
aMarCruz 给出的答案很有效。但是,如果您还需要将自定义道具传递给 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>
只是在这里添加完成。
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';