Search code examples
reactjstypescripttypechecking

Typecheck error while passing an array of ReactNode to a functional component


I have a component which is passing an Array of ReactNode to another component.

    const getOptions = (links: Array<Links>): Array<ReactNode> => {
        const options: Array<ReactNode> = [];
        links.map((link): void => {
            options.push(
                <Link
                    href={link.path}
                    key={link.page}
                >
                    {link.label}
                </Link>
            );
        });
        return options;
       };
<<<<<some code>>>>>>
<Dropdown dropDownOptions={getOptions(dropdownLinks)} />

My Dropdown component:

const Dropdown = ({ dropDownOptions }: any): JSX.Element => {}

so the problem I have here is when I use any as dropdown option type I get a warning:

Object pattern argument should be typed with a non-any type

But when I use Array as a type I get the following error:

Property 'dropDownOptions' does not exist on type 'any[]'

I am not sure how to resolve this.


Solution

  • If you're specifying a type on a destructured property, you need the same structure in the type signature as well, so instead of { dropDownOptions }: Array<ReactNode>, it needs to be

    const Dropdown = ({ dropDownOptions }: { dropDownOptions: Array<ReactNode> }) => (
      <div>...</div>
    )
    

    or just

    const Dropdown = ({ dropDownOptions }: { dropDownOptions: ReactNode[] }) => (
      <div>...</div>
    )
    

    As an unrelated note, the code uses map, but it's not an actual map as it builds the result with side effects and discards the returned array. You could rewrite it as a purely functional map like this:

    const getOptions = (links: Array<Links>) =>
      links.map(link => (
        <Link href={link.path} key={link.page}>
          {link.label}
        </Link>
      ))
    

    The return-type signatures will all be inferred by the compiler.

    TypeScript playground