Reputation: 1440
I have written a React dropdown component which I can supply either of the following to :
string
stext
and icon
.My simple flow types look as follows:
type DropdownMenuItemType = DropdownMenuIconAndTextType | string;
type DropdownMenuIconAndTextType ={
text: string,
icon?: React$Element<React$ElementType>;
}
Previous versions of the component only supports strings. The addition of an element to support text
and an icon
is a new feature request which I am in the process of implementing. I don't want any breaking changes for my existing users.
Therefore within my component I try to attempt to convert any string
supplied and wrap it in a DropdownMenuIconAndTextType
so everything ends up as this type. Items that are already DropdownMenuIconAndTextType
just remain so.
let Array<DropdownMenuItemType> originalItems =
let Array<DropdownMenuIconAndTextType> convertedItems = [];
{'English', 'French', 'German', {text: 'Dutch', icon : <SomeIcon />}};
items.forEach( (currItem: DropdownMenuItemType) => {
if(typeof currItem === DropdownMenuIconAndTextType){
convertedItems.push(currItem);
}
else {
convertedItems.push({text: currItem.toString()});
}
});
However flow has one error with :
if(typeof currItem === DropdownMenuIconAndTextType){
convertedItems.push(currItem);
}
and it says that currItem
could still be a string
and is incompatible with convertedItems
despite it being type checked as DropdownMenuIconAndTextType
.
What do I need to do to satisfy flow in this scenario ? Thanks in advance.
Upvotes: 1
Views: 143
Reputation: 348
I believe you're mixing up the distinction between Flow's type code and JS code.
Inside of type signatures, typeof
returns the type of a literal value, as described here. In the JS code that exists at runtime, such as in your if
statement, typeof
will just tell you whether something is a string, object, etc., as described here. So the left side of your conditional operator will evaluate to either "string"
, or "object"
, not to the actual Flow type of the variable.
On the right side of your conditional, you have the Flow type DropdownMenuIconAndTextType
, which only exists at type-checking time, not at runtime. I'm kind of surprised that Flow doesn't give you an error because of that.
Try something like this:
if(typeof currItem !== 'string'){
convertedItems.push(currItem);
}
This will check whether the value that exists at runtime is a string or an object, which should work with Flow's type refinements.
Upvotes: 2