giveearholdtongue
giveearholdtongue

Reputation: 5

How can I declare type on mapped elements?

I'm getting an error on the className of mapped elements. I believe TS is throwing the error because the map's children (MenuItem) don't have the className type. See the error below.

The mapped elements are part of the headlessui package. I think this is part of the reason I'm having trouble. I'm following this introduction to headlessui: https://headlessui.com/react/menu. This example is the third code sample on that page.

I tried to make the MenuItemProps interface to use on the .map function like this:

links.map((link): MenuButtonInterface => ()

How can I include the className type to the children of the .map function?

ERROR:

Type '{ children: Element; key: string; className: string; }' is not assignable to type 'IntrinsicAttributes & CleanProps<ExoticComponent<{ children?: ReactNode; }>, "disabled" | ItemPropsWeControl> & OurProps<...> & { ...; } & { ...; }'.


Property 'className' does not exist on type 'IntrinsicAttributes & CleanProps<ExoticComponent<{ children?: ReactNode; }>, "disabled" | ItemPropsWeControl> & OurProps<...> & { ...; } & { ...; }'.ts(2322)

import React, { ReactNode } from 'react'
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react'

const links = [
    {href: '/home', label: 'Home'},
    {href: '/Test', label: 'Test'},
    {href: '/settings', label: 'Settings'}
]

interface MenuItemProps{
    children: any
    className?: any
    key: any
}

export const MyComponent = () => {
    return(
        <Menu>
            <MenuButton className='data-[active]:bg-blue-500'></MenuButton>
            <MenuItems anchor='bottom'>
                {links.map((link) => (
                    <MenuItem key={link.href} className='block data-[focus]:bg-blue-500'>
                        <a href={link.href}>{link.label}</a>
                    </MenuItem>
                ))}
            </MenuItems>
        </Menu>
    )
}

Upvotes: 0

Views: 69

Answers (2)

Bhavesh Kumar Sharma
Bhavesh Kumar Sharma

Reputation: 373

the issue that I can see is that you are not using the interface "MenuItemProps" that you have created in your component.

Since you are using Headlessui which already has it's own types, you can either use

  1. type assertion

<MenuItem as="div" className="block data-[focus]:bg-blue-500" {...({ key: link.href, children: <a href={link.href}>{link.label}</a>, } as MenuItemProps)} // Type assertion here />

  1. Create a small component, use you interface there and use it in the code

// Custom component for handling props
const CustomMenuItem: React.FC < MenuItemProps > = ({
  children,
  className,
  key,
}) => {
  return ( <
    MenuItem as = "div"
    key = {
      key
    }
    className = {
      className
    } > {
      children
    } <
    /MenuItem>
  );
};

// Use it in the code
{
  links.map((link) => ( <
    CustomMenuItem key = {
      link.href
    }
    className = "block data-[focus]:bg-blue-500" >
    <
    a href = {
      link.href
    } > {
      link.label
    } < /a> <
    /CustomMenuItem>
  ))
}

**Note: Answer below using

as Prop

works fine as well.**

Upvotes: 0

Islombek Salimov
Islombek Salimov

Reputation: 14

Use as Prop Directly on MenuItem

According to the docs you can use the as prop directly in MenuItem to render an a tag and it will allow you to pass the className

Code will look like this:

<MenuItem
  key={link.href}
  as="a"
  href={link.href}
  className="block data-[focus]:bg-blue-500"

{ link.label }
</MenuItem>

Hope this helps you.

Upvotes: 0

Related Questions