Ethan Keshishian
Ethan Keshishian

Reputation: 83

Typescript complications with string unions

I'm trying to create a function that returns JSX depending on the name prop. Here's my code:

function TabBarIcon(props: {
  name:
    | React.ComponentProps<typeof Ionicons>['name'] // 'key' | 'item' | 2000 more...
    | React.ComponentProps<typeof Feather>['name']; // 2000 different strings...
  color: string;
  type: 'Ionicons' | 'Feather';
}) {
  if (props.type === 'Ionicons')
    return <Ionicons size={30} style={{ marginBottom: -3 }} {...props} />;
  else if (props.type === 'Feather')
    return <Feather size={30} style={{ marginBottom: -3 }} {...props} />;
  else return <View />;
}

TypeScript throws an error because it can't be sure the <Ionicons /> and <Feather /> components contain name. I've attempted to workaround this with props.type, but TypeScript still throws an error. How can I return the correct component without the error? Thanks!

Upvotes: 0

Views: 768

Answers (1)

Linda Paiste
Linda Paiste

Reputation: 42188

It looks like Ionicons has over 3,000 names while Feather has more like 300. What happens if I call your component with type="Feather" and a name that only exists on Ionicons?

Your component is typed such that a name is a valid prop if it exists on either Ionicons or Feather. But that's not good enough. We need to know that the icon exists on the chosen icon set.

Defining the props as a union will make the error go away.

function TabBarIcon(props: { 
  color: string;
} & (
  {
    name: React.ComponentProps<typeof Ionicons>['name'];
    type: 'Ionicons';
  } | {
    name: React.ComponentProps<typeof Feather>['name'];
    type: 'Feather';
})) {
  if (props.type === 'Ionicons')
    return <Ionicons size={30} style={{ marginBottom: -3 }} {...props} />;
  else if (props.type === 'Feather')
    return <Feather size={30} style={{ marginBottom: -3 }} {...props} />;
  else return <View />;
}

Upvotes: 2

Related Questions