键入一个克隆其子项的 React 组件以在 TypeScript 中添加额外的道具

shu*_*ksh 7 javascript typescript reactjs typescript-typings

假设您有以下组件接受一个或多个子 JSX.Elements 并在使用React.cloneElement(child, { onCancel: () => {} }.

有问题的组件(摘录):

interface XComponentProps {
    onCancel: (index: number) => void;
}

class XComponent extends React.Component<XComponentProps> {
    render() {
        const { onCancel } = this.props;
        const children = typeof this.props.children === 'function' ?
            React.cloneElement(this.props.children, { onCancel: () => onCancel() }) :
            this.props.children.map((child, idx) => (
                React.cloneElement(child, { onCancel: () => onCancel(idx) })
            ));
        return <div>{children}</div>;
    }
}
Run Code Online (Sandbox Code Playgroud)

正在运行的相关组件(摘录):

interface UserComponentProps { caption: string }
const UserComponent = (props: UserComponentProps) => (
    <button onClick={props.onClose}>{props.caption || "close"}</button>
);

ReactDOM.render(
    <XComponent onCancel={handleCancel}>
        <UserComponent />
        <UserComponent />
        <UserComponent />
    </XComponent>
);
Run Code Online (Sandbox Code Playgroud)

眼下TSC抱怨并UserComponent没有onCancel在它的道具界面定义,确实没有。一个最简单的解决方法是手动定义onCancelUserComponentProps接口。

但是,我想在不修改子节点的 prop 定义的情况下修复它,以便组件可以接受任意一组 React 元素。在这种情况下,有没有办法定义返回元素的类型,这些元素在XComponent(父)级别传递了额外的隐式道具?

Ben*_* B. 4

这不可能。无法静态地知道 UserComponent 从 ReactDOM.render 上下文中的父 XComponent 接收到哪些 props。

如果您想要类型安全的解决方案,请使用子函数:

这是XComponent定义

interface XComponentProps {
    onCancel: (index: number) => void;
    childrenAsFunction: (props: { onCancel: (index: number) => void }) => JSX.Element;
}

class XComponent extends React.Component<XComponentProps> {
    render() {
        const { onCancel } = this.props;
        return <div>{childrenAsFunction({ onCancel })}</div>;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以用它来渲染你UserComponent

<XComponent onCancel={handleCancel} childrenAsFunction={props => 
  <span>
    <UserComponent {...props} />
    <UserComponent {...props} />
  </span>
} />
Run Code Online (Sandbox Code Playgroud)

这会很好地工作,我经常使用这种模式,没有任何麻烦。您可以重构 XComponentProps 以childrenAsFunction使用相关部分(onCancel此处的函数)键入 prop。