I am having trouble with setting proper types for react children.
export const recursiveCloneChildren = (
children: React.ReactNode,
handleChildChange,
disableContent: boolean,
) => {
return React.Children.map(children, (child) => {
if (!isObject(child)) {
return child;
}
let childProps = {
...child.props,
disabled: child.props.disabled || disableContent,
};
const requiredOrValidatableChildProps = {
...childProps,
checkValidationState: handleChildChange,
};
if (child.props.required || child.props.validatable) {
childProps = {
...requiredOrValidatableChildProps,
};
}
if (child.props.children) {
childProps.children = recursiveCloneChildren(child.props.children, handleChildChange, disableContent);
}
return React.cloneElement(child, childProps);
});
};
I am getting this error
Property 'props' does not exist on type '{} | ReactElement<any, string | JSXElementConstructor> | ReactNodeArray | ReactPortal'.
Property 'props' does not exist on type '{}'.
I tried to set types for child directly ( React.ReactChild ), and showed another error on children. How can it be solved?
CodePudding user response:
I don't really like what you're trying to do, because if I found it in a codebase I'd be really confused.
But to answer your question. The child
argument in the function passed to Children.map
is of type ReactNode
. This is the most general type, meaning you can end up with pretty much anything that can be a valid child. I actually don't know if your code is going to work but considering you want to access props, I'm assuming what you want is to make sure you're operating on ReactElement
. In that case, your isObject
check is not exhaustive enough. What you need is a type guard.
So the quick and dirty option is to write your own type guard and something like this is actually enough:
function isReactElement(child: React.ReactNode): child is React.ReactElement {
return isObject(child) && 'props' in child;
}
and then instead of
if (!isObject(child)) {
return child;
}
you just do
if (!isReactElement(child)) {
return child;
}
and it works. However probably a better idea is to use react-is
library which is an official, Facebook-maintained library and it's widely used in many React libraries and it does basically exactly what you want but the checks are significantly better than what I proposed above. In your case you'd want to use isElement
, the same way I showed above. Just make sure to install @types/react-is
, too.