0

I'm coding a component that will return the icon corresponding to the passed prop as follows (simplified version of my app):

import * as icons from "@mui/icons-material";

interface IGenericIconProps {
  iconName: keyof typeof icons;
}

export const GenericIcon = ({ iconName }: IGenericIconProps): JSX.Element => {
  const Icon = icons[iconName];
  return <Icon />;
};
import GenericIcon from './GenericIcon';

interface IUseGenericIconProps {
  randomIcon: string; // the error goes away if I change this to 'any'
}

const UseGenericIcon = ({randomIcon}: IUseGenericIconProps): JSX.Element => {
  return (
    <GenericIcon iconName={randomIcon}/>
  )
}

Then in another file I have

import UseGenericIcon from './UseGenericIcon';

enum MyIcons {
  Task = "TaskOutlined",
  Reminder = "AlarmOutlinedIcon",
  Other = "AnnouncementOutlinedIcon",
}

const Calendar = () => {
  return (
    <UseGenericIcon randomIcon={MyIcons.Task}/>
  )
}

This ends up throwing an Typescript error:

Type 'string' is not assignable to type '"Abc" | "AbcOutlined" | "AbcRounded" | "AbcSharp" | "AbcTwoTone" | "AcUnit" | "AcUnitOutlined" | "AcUnitRounded" | "AcUnitSharp" | "AcUnitTwoTone" | "AccessAlarm" | "AccessAlarmOutlined" | ... 9875 more ... | "ZoomOutTwoTone"'.ts(2322)

As noted, I can change the type from string to any and it will work, but I would like to know how can I fix this type error for future use. They both seem to be strings to me.

I got the implementation idea from Rendering Material-UI icons from an array

XueXu
  • 69
  • 2
  • 8

2 Answers2

1

In IGenericIconProps you specify that an iconName must be of type keyof typeof icons. This type is stricter than just string; it's looking for a specific set of string literals that are the keys of the icons object. By then having randomIcon: string in IUseGenericIconProps, you've relaxed the type to be any string and so Typescript rightfully complains. Changing it to any simply removes all type safety. Why not export that type and use it everywhere instead?

import * as icons from "@mui/icons-material";

export type IconNames = keyof typeof icons // use this in other components

interface IGenericIconProps {
  iconName: IconNames;
}

export const GenericIcon = ({ iconName }: IGenericIconProps): JSX.Element => {
  const Icon = icons[iconName];
  return <Icon />;
};
Sam A.
  • 666
  • 4
  • 6
0

I had a similar problem, I ended up fixing it like this:

import React, { FC } from 'react'
import * as Icons from '@mui/icons-material'

type IconNames = keyof typeof Icons
type CustomIconProps = {
  iconName: IconNames
}

export const IconComponent: FC<CustomIconProps> = ({
  iconName,
}) => {
  const Icon = Icons[iconName]
  return <Icon />
}

Not exactly like your code but it might be help-full

MarvinVK
  • 2,964
  • 1
  • 22
  • 21