How to use an Intrinsic attributes as types in TypeScript react-native

Viewed 586

How do you make use of Intrinsic attributes as types in typeScript.

I have a simple tab navigation that looks like:

  const getOptions = (iconName: string) => ({
    tabBarIcon: ({ color }: { color: string }) => (
      <MaterialIcons name={iconName} size={24} color={color} />
    ),
  });


<Tab.Navigator>
      <Tab.Screen
        name="HomeScreen"
        component={HomeScreen}
        options={() => getOptions("home")}
      />
</Tab.Navigator>

MaterialIcons from @expo/vector-icons has a property name which is of type GLYPHS.

When I use iconName: string I get the following error:

The expected type comes from property 'name' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes

What am I doing wrong?

1 Answers

The problem is that the property name of the MaterialIcons component expects a String literal type, whilst you're trying to assign a string type to it.

Because there is not an exported String literal type from the @types/react-native-vector-icons or in the @expo/vector-icons package, you'll have to define your own type for it.

A possible solution would be to declare the type of the iconName attribute to be of type 'home' instead of string:

const getOptions = (iconName: 'home') => ({
  tabBarIcon: ({ color }: { color: string }) => (
    <MaterialIcons name={iconName} size={24} color={color} />
  ),
});


<Tab.Navigator>
    <Tab.Screen
      name="HomeScreen"
      component={HomeScreen}
      options={() => getOptions("home")}
    />
</Tab.Navigator>

You would have to extend this type if you would need more icon names in it, of course. For example if you want to add an article screen to your Tab.Navigator in the future:

// iconName is of 'home' | 'article' string literal type now
const getOptions = (iconName: 'home' | 'article') => ({
  tabBarIcon: ({ color }: { color: string }) => (
    <MaterialIcons name={iconName} size={24} color={color} />
  ),
});

<Tab.Navigator>
  <Tab.Screen name="HomeScreen" component={HomeScreen} options={() => getOptions('home')} />
  <Tab.Screen
    name="ArticleScreen"
    component={ArticleScreen}
    options={() => getOptions('article')}
  />
</Tab.Navigator>;
Related