Assuming you have following component that accepts one or more child JSX.Elements and passes extra callback to their props when they are rendered by using React.cloneElement(child, { onCancel: () => {} }
.
Component in question (excerpt):
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>;
}
}
Component in question in action (excerpt):
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>
);
Right now TSC is complaining that UserComponent
does not have onCancel
in its props' interface definition, which indeed does not. One easiest fix is to manually define onCancel
to UserComponentProps
interface.
However, I want to fix it without modifying child node's prop definition so that the component can accept arbitrary set of React elements. In such scenario, is there a way to define typings of returning elements that has extra implicit props passed at the XComponent
(parent) level?
It is not possible. There is no way to know statically what props UserComponent receives from parent XComponent in your ReactDOM.render context.
If you want a type safe solution, use children as functions:
Here is XComponent
definition
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>;
}
}
Now you can use it to render your UserComponent
s
<XComponent onCancel={handleCancel} childrenAsFunction={props =>
<span>
<UserComponent {...props} />
<UserComponent {...props} />
</span>
} />
This will work nicely, I use this pattern often with no hassle.
You can refactor XComponentProps to type the childrenAsFunction
prop with the relevant part (the onCancel
function here).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With