Búsqueda de sitios web

reactjs - ¿Cómo extender la interfaz TS para un componente React (MUI) usando styled-components?


He estado tratando de averiguar cómo resolver este problema de sobrecarga y hasta ahora nada. Estoy usando Typescript, Styled-components y material-ui. Estoy usando styled(MUIButton) para ampliar el Button nativo de MUI. A través de console.logs puedo ver que mis props están pasando al componente, sin embargo no sé cómo establecer la tipificación para que el error de sobrecarga desaparezca.

¿Alguna opinión?

artículos relevantes: ¿Cómo ampliar las props para los componentes de Material-UI usando Typescript?

error :

código :

import { default as MUIButton, ButtonProps } from '@material-ui/core/Button';
import styled, { css } from 'styled-components';
import { darken } from '@material-ui/core/styles';

interface IButton extends ButtonProps {
  format?: 'primary' | 'secondary';
  variant?: 'contained' | 'outlined' | 'text';
  label: string;
}

const Button = ({ format, variant, label }: IButton): JSX.Element => (
  <StyledButton format={format} variant={variant}>
    {label}
  </StyledButton>
);

Button.defaultProps = {
  format: 'primary',
  variant: 'contained',
};

export default Button;

const StyledButton = styled(MUIButton)<IButton>`
  //? contained variant (default)
  ${({ format, theme }) => `
  background-color: ${
    format === 'primary'
      ? theme.palette.colors.main
      : theme.palette.colors.secondary
  };
  color: ${theme.palette.font.secondary};
  font-weight: ${theme.agnosticStyles.font.weight.bold};
  padding: .7rem 4rem;
  &:hover {
    background-color: ${darken(theme.palette.colors.main, 0.2)};
  }
  `}
...
}

Respuesta #1

No está completamente claro cómo se ve tu componente StyledButton. El Button original de @material-ui/core no acepta la propiedad format. Y de eso se trata exactamente este error.

Si de alguna manera consumes esta propiedad directamente en tu StyledButton, deberías escribir su tipo en consecuencia:

const StyledButton = styled(MUIButton)<{format?: 'primary' | 'secondary'}>``;

Aunque tal vez estés buscando la propiedad color que el Button original acepta y que puede aceptar tanto valores primary como secondary.

Respuesta #2

Eso es porque format es una propiedad personalizada y necesitas pasarla como argumento al elemento StyleButton.

Como ya creaste la interfaz IButton, puedes usarla así:

const StyledButton = styled(MUIButton)<IButton>`
   ${props => console.log(props)}
   ...
`;

Con el código anterior también necesitarás configurar el label en tu interfaz como nullable (si no lo haces, obtendrás un error Property 'label' is missing in type):

interface IButton extends ButtonProps {
  format?: "primary" | "secondary";
  variant?: "contained" | "outlined" | "text";
  label?: string;
}

const Button = ({ format, variant, label }: IButton): JSX.Element => (
  <StyledButton format={format} variant={variant}>
    {label}
  </StyledButton>
);

<Button label={"test"} format={"primary"} variant={"contained"} />

Otro enfoque es configurar tu Botón como un FunctionComponent y entonces, ya no necesitarás la propiedad label y podrás usar children en su lugar:

interface IButton extends ButtonProps {
  format?: "primary" | "secondary";
  variant?: "contained" | "outlined" | "text";  
}

const StyledButton = styled(MUIButton)<IButton>`
   ...
`;

const Button: React.FC<IButton> = ({ format, variant, children }) => (
   <StyledButton format={format} variant={variant}>
      {children}
   </StyledButton>
);

<Button format={"secondary"} variant={"text"}>
   Test
</Button>

Puedes obtener más información sobre las propiedades personalizadas en styled-components aquí

Actualizado

Si reemplazas format por color en <StyledButton>, obtendrás el estilo de botón deseado.

interface IButton extends ButtonProps {
  format?: "primary" | "secondary";
  variant?: "contained" | "outlined" | "text";  
}

const StyledButton = styled(MUIButton)<IButton>`
   ...
`;

const Button: React.FC<IButton> = ({ format, variant, children }) => (
   
   // ******
   // HERE'S THE TRICK -> INSTEAD FORMAT, YOU SHOULD SET COLOR
   // ******
   <StyledButton color={format} variant={variant}>
      {children}
   </StyledButton>
);

<Button variant={"contained"} format={"primary"}>
   primary
</Button>
<Button variant={"outlined"} format={"secondary"}>
   secondary
</Button>