React Material UI v5 TypeScript inherit component type

Viewed 386

How to inherit MUI component type with props and add extra props with minimum imported stuff? If possible without giving types to props, only to component itself. Also I want to keep the ability of component to accept render component prop types: Button<typeof Link> with prop: component={Link}

import { Button as MuiButton } from '@mui/material'


const Button: typeof MuiButton = (props) => ...   
// this says props has type: any


const Button: ExtendButtonBase<ButtonTypeMap> = () => ....  
// this same:   props: any. I prefer not to import more stuff and use typeof MuiButton


const Button: typeof MuiButton = (props: ButtonProps<any>) => ....   
// this works for default component props, but does not accept additional custom props. 
// Also if possible without giving extra types to props, only to component


interface ExtraProps {
    test?: string
}

const Button: typeof MuiButton = (props: ButtonProps<any, ExtraProps>)
// when ExtraProps has required property it gives errors, but not when they are only optional
// this does not makes error when creating the component, but it makes when using it.


const Button = <C extends React.ElementType>(props: ButtonProps<C, {component?: C}> & ExtraProps) => ...
// This one works, but it does not feel like good implementation

const Button: OverridableComponent<ButtonTypeMap<ExtraProps>> = (props) => ...
// this works, but I can not use Component.defaultProps / propTypes. Also props has type: any

What is the best working way of doing this?

1 Answers

Maybe you can override ButtonPropsVariantOverrides declaration then customize the theme by adding style to your variants:

Here is an example with Button

declare module '@mui/material/Button' {
  interface ButtonPropsVariantOverrides {
    shape?: 'normal' | 'rounded' | 'square';
  }
}

Then you would need to override this component, see https://mui.com/material-ui/customization/theme-components/#adding-new-component-variants

import { Theme } from '@mui/material/styles';

export default function Button(theme: Theme) {
  return {
    MuiButton: {
      variants: [
        {
          props: { shape: 'normal' },
          style: {
             // actually, nothing to place here
          },
        },
        {
          props: { shape: 'square' },
          style: {
            borderRadius: 0,
          },
        },
        {
          props: { shape: 'rounded' },
          style: {
            borderRadius: 10 * Number(theme.shape.borderRadius),
          },
        }
      ]
    },
  };
}
Related