During the recent code refactoring, I have a question that I do not understand. First of all, here's what I've been working on:
// CustomTracks.tsx
import { faList } from '@fortawesome/free-solid-svg-icons';
import styled from 'styled-components';
import Icon from '../../../../components/atom/Icon';
import LinkElement from '../../../../components/atom/LinkElement';
const MenuItem = styled.li`
* {
width: 25px;
height: 25px;
}
Link,
LogoutButton {
padding: 5px;
}
`;
function CustomTracks() {
return (
<MenuItem>
<LinkElement
LinkStyle={undefined}
linkText={<Icon icon={faList} />} // Attributes you want to filter on
title="Favorite track list"
to="/tracks/custom"
/>
</MenuItem>
);
}
export default CustomTracks;
// Link.tsx
import { Link, LinkProps } from 'react-router-dom';
import { StyledComponent } from 'styled-components';
export interface LinkElementProps {
to: string;
linkText: string | JSX.Element; // what actually worked
title?: string;
LinkStyle?: StyledComponent<
React.ForwardRefExoticComponent<
LinkProps & React.RefAttributes<HTMLAnchorElement>
>,
any,
{},
never
>;
}
function LinkElement({ to, title, linkText, LinkStyle }: LinkElementProps) {
return LinkStyle ? (
<LinkStyle to={to} title={title ? title : ''}>
{linkText}
</LinkStyle>
) : (
<Link to={to}>{linkText}</Link>
);
}
export default LinkElement;
I want the linkText property of the Link component to accept only string and Icon components. But as you can see, the type of linkText is string | Since it is JSX.Element, it is designed to allow any component, not just the Icon component. I don't know what to do to solve this.
CodePudding user response:
This is not possible in TypeScript because there is no way to know the type of the object passed, since it all comes down to a JSX.Element
. The only workaround that comes in mind would be to display an error message at runtime, and return null
or something else, like this:
function LinkElement({ to, title, linkText, LinkStyle }: LinkElementProps) {
if (
typeof linkText !== 'string' &&
'type' in linkText &&
linkText.type.name !== Icon.name
) {
console.log('Wrong component type for LinkElement, only accepting Icon!');
return null
}
return LinkStyle ? (
<LinkStyle to={to} title={title ? title : ''}>
{linkText}
</LinkStyle>
) : (
<Link to={to}>{linkText}</Link>
);
}
There is an open issue regarding this here.