Home > front end >  How to filter only specific components in Typescript
How to filter only specific components in Typescript

Time:10-07

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.

  • Related