Home > database >  Creating Dot Notation Functional Component with Typescript/ReactJS
Creating Dot Notation Functional Component with Typescript/ReactJS

Time:11-26

I am trying to work out how to create a dot notation component and everything I've found on SO and Google doesn't appear to work in the way that I am expecting.

I have the following code for two components, at the moment its all in one file

const ThreeDotMenu : any = ({children}) => {
    return (
        <>
            <ul className='absolute bg-primary-light text-white'>
                {children}
            </ul>
        </>
    )
}

const Item : React.FC<DefaultProps> = ({children}) => {
    return (
        <li>{children}</li>
    )
}

ThreeDotMenu.Item = Item;
export default ThreeDotMenu;

And I am using it as follows:

<ThreeDotMenu>                                                                            
   <ThreeDotMenu.Item>item</ThreeDotMenu.Item>                                                                         
   <ThreeDotMenu.Item>item 2</ThreeDotMenu.Item>
</ThreeDotMenu>

This is working fine except the parent component isn't type instead I am using any as the type.

I am now trying to type it by changing the declaration to be:

const ThreeDotMenu : React.FC<DefaultProps> = ({children}) => {}

The component itself is happy, however the declaration where I do ThreeDotMenu.Item = Item now throws an error with the following:

Property 'Item' does not exist on type FC

And my DefaultProps is typed as follows:

export interface DefaultProps {
    children: Array<React.ReactNode>|React.ReactNode
}

CodePudding user response:

You can work around this by having a .Menu component that acts as the parent component.

import React from 'react';

const Menu: React.FC<DefaultProps> = ({children}: any) => {
    return (
        <>
            <ul className='absolute bg-primary-light text-white'>
                {children}
            </ul>
        </>
    )
}

const Item: React.FC<DefaultProps> = ({children}) => {
    return (
        <li>{children}</li>
    )
}


const ThreeDotMenu = {Menu, Item}
export default ThreeDotMenu

<ThreeDotMenu.Menu>                                                                            
        <ThreeDotMenu.Item>item</ThreeDotMenu.Item>                                                                         
        <ThreeDotMenu.Item>item 2</ThreeDotMenu.Item></ThreeDotMenu.Menu>

playground

If you want to use the parent without the dot, you can just let the compiler figure the types out instead of giving explicit types.


const ThreeDotMenu = ({ children }) => {
  return (
    <>
      <ul className="absolute bg-primary-light text-white">{children}</ul>
    </>
  );
};

const Item = ({ children }) => {
  return <li>{children}</li>;
};

ThreeDotMenu.Item = Item;

export default function App() {
  return (
    <ThreeDotMenu>
      <ThreeDotMenu.Item>item</ThreeDotMenu.Item>
      <ThreeDotMenu.Item>item 2</ThreeDotMenu.Item>
    </ThreeDotMenu>
  );
}

CodePudding user response:

The simplest way is to not use React.FC, as suggested in @nullptr's answer.

If you really want to use it, you can add an intersection with your extra properties that you assign later on:

const ThreeDotMenu: React.FC<DefaultProps> & {
    Item: typeof Item
}

Playground Link

  • Related