如何正确键入 React.Children 和 React.cloneElement?

nce*_*sar 2 typescript reactjs typescript-typings

我正在用 cloneElement 克隆我的反应孩子,但我在输入它们时遇到了一些问题。

这是我的代码(它只是将自定义 onClick 函数作为道具传递给孩子们):

const childrenWithProps = React.Children.map(children, child =>
  React.cloneElement(child as ReactChild, {
    onClick: (e: React.FormEvent) =>
      childrenClickHandler(
        e,
        child.props.children,
        onItemClick && onItemClick(e),
      ),
  }),
);
Run Code Online (Sandbox Code Playgroud)

这是我的ReactChild类型:

export type ChildProps = {
  onClick?: (e?: React.ChangeEvent<{}>) => void;
  props: React.Props<ReactChild>;
  children: ReactElement | ReactElement[];
};
export type ReactChild = ReactElement<ChildProps> | ReactElement;
Run Code Online (Sandbox Code Playgroud)

而且打字稿一直说我的propson有问题child.props.children

在此处输入图片说明

消息是:

“ReactNode”类型不存在属性“props”。'string' 类型不存在属性 'props'。

我做错了什么?

law*_*itt 5

您收到消息的原因:

“ReactNode”类型不存在属性“props”。'string' 类型不存在属性 'props'。

是因为 aReactNode可以是组件、html 元素或纯字符串。字符串不接受道具。我发现您需要做的就是清除它是有效 React 元素的正确类型保护:

const childrenWithProps = React.Children.map(children, child => {
    if (React.isValidElement(child)) {
        return React.cloneElement(child, {newProp: 'myNewProp'})
    }

    return child;
});
Run Code Online (Sandbox Code Playgroud)


Shl*_*ang 2

您可以将类型移动/添加到回调的参数中,map因为现在它仅适用于 的第一个参数React.cloneElement

const childrenWithProps = React.Children.map(children, (child: ReactChild) => // <- Here
  React.cloneElement(child, { // <- Assertion here can be omitted
    onClick: (e: React.FormEvent) =>
      childrenClickHandler(
        e,
        child.props.children,
        onItemClick && onItemClick(e),
      ),
  }),
);
Run Code Online (Sandbox Code Playgroud)

断言与变量具有相同的作用域,因此

React.Children.map(children, child => ...)
Run Code Online (Sandbox Code Playgroud)

没有类型会产生child类型any(如果您没有以某种方式指定类型children

thenchild用作参数,根据函数的类型和您的 tsconfig,它可能需要某种类型的值

React.cloneElement(child, ...)
Run Code Online (Sandbox Code Playgroud)

您将断言放在这里,但它会影响 as 参数的使用child。实际上,可以将相同的断言应用于第二种用法:

  React.cloneElement(child as ReactChild, {
    onClick: (e: React.FormEvent) =>
      childrenClickHandler(
        e,
        (child as ReactChild).props.children, // <- Here
        onItemClick && onItemClick(e),
      ),
  }),
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,最好指定定义变量的类型,以便它在所有范围内都具有相同的类型。