简体   繁体   中英

Flow type for React props.children (union Element | Array)

I have a container component and it's props type with children property:

type Props = {
    children: Array<React.Element<any>> | React.Element<any>,
    settings: string | Object
};

Container can contain the only one React.Element or multiple and depends on that it should choose the right operation.

In the render function I have something like that:

const children = this.props.children;

if ( _.isArray(children) ) {
    return _.map(children, (child, key) => checkListComponent(child, key));
}

else if ( _.isObject(children) ) {
    return checkListComponent(children);
}

The main function is that:

const checkListComponent = (child: React.Element<any>, key) => {
        return child.props.list
            ? React.cloneElement(child, key ? { options, key } : { options })
            : child;
    };

And after all I get a Flow error in else if

return checkListComponent(children);

Flow: array type. This type is incompatible with the expected param type of React$Element.

It seems to ignore possible type of non Array for the children prop. I found issue on Github about union Array and Object type but there is nothing.

Is there any solution for that situation?

UPD:

The same problem I have with props.settings , it can be an API url to fetch settings object from the server or a direct settings object. When I call an axios.get(settings) (obviously check before that props.settings is a string for now) Flow ignores possible string type and complains that Object given instead of string. BUT in the next line when I check settings for an object type and set container state

this.setState({ settings: this.props.settings });

It complains that String given instead of Object .

How it is possible and what can I do with that? I can but don't want to have two different props for settings API and Object. And definitely this is impossible for the props.children part of a problem.

Flow has no way to know that _.isArray returning true means that children is an array, and the same applies to _.isObject . Your code should work as

const children = this.props.children;

if (Array.isArray(children) ) {
  return children.map((child, key) => checkListComponent(child, key));
} else {
  return checkListComponent(children);
}

since Array.isArray is standard and Flow can know that in the else block children must be the the non-array type in your union.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM