Encountered a problem where I do not know how to work-around this in strongly typed variables.
So, I have a bunch of icons as components and an icon wrapper component.
Wrapper component has themeMode
variable in order to determine in what color should icon be displayed. Hence, every icon needs themeMode
variable, which is mandatory. However, I cannot think of the workaround when I have to pick an icon based of switch case scenario.
Here is the code for better understandment:
This component gets an id from a url and displays certain icon component.
However, every switch cases returning statements are underlined in red. That's because icon component NEEDS that themeMode
variable. However, I'm giving it on iconWrapper component.
const CollectionEnd = () => {
const { id } = useParams();
const getEndSvg = () => {
switch (id) {
case "bags":
return <Bags />;
case "shoes":
return <Shoes />;
case "men":
case "women":
return <Clothes />;
case "hats":
return <Hats />;
default:
return <Clothes />;
}
};
return (
<Container>
<IconWrapper Component={getEndSvg()} />
</Container>
);
};
Icon wrapper component:
const IconWrapper: React.FC<{
Component: React.FC<{
themeMode: string;
style?: React.CSSProperties;
isOpened?: boolean;
}>;
isOpened?: boolean;
otherProps?: React.ReactNode;
style?: React.CSSProperties;
}> = ({ Component, style, isOpened, ...otherProps }) => {
const themeMode = useAppSelector(selectThemeMode);
return (
<div style={style}>
<Component {...otherProps} isOpened={isOpened} themeMode={themeMode} />
</div>
);
};
Here is one of the icon component's emitted code:
const Bags: React.FC<{ themeMode: string }> = ({ themeMode }) => {
return (
<svg
id='svg'
xmlns='http://www.w3.org/2000/svg'
width='200'
height='200'
viewBox='0, 0, 400,400'
version='1.1'
>
-----> ...emitedCode <------
Yes, I can simply make themeMode
as not required, but that is not good. Also, I can wrap all switch case scenarios in IconWrapper. However, it looks repetitive.
CodePudding user response:
One approach could be to change IconWrapper
to accept React.ElementType
and to pass the Icon
component rather than an instantiated JSX.Element. This would let you delegate instantiating the Icon
component to IconWrapper
, which has the themeMode
available.
In practice, this would look something like:
const CollectionEnd = () => {
const { id } = useParams();
const getEndSvg = () => {
switch (id) {
case "bags":
return Bags;
case "shoes":
return Shoes;
case "men":
case "women":
return Clothes;
case "hats":
return Hats;
default:
return Clothes;
}
};
return (
<Container>
<IconWrapper Component={getEndSvg()} />
</Container>
);
};
const IconWrapper: React.FC<{
Component: React.ElementType<{
themeMode: string;
style?: React.CSSProperties;
isOpened?: boolean;
}>;
isOpened?: boolean;
otherProps?: React.ReactNode;
style?: React.CSSProperties;
}> = ({ Component, style, isOpened, ...otherProps }) => {
const themeMode = useAppSelector(selectThemeMode);
return (
<div style={style}>
<Component {...otherProps} isOpened={isOpened} themeMode={themeMode} />
</div>
);
};