reactjstypescriptmaterial-uibase-ui

Styled Base UI component with parameter throws TypeScript error


This tsx code:

import React from "react";
import BaseButton from "@mui/base/Button";
import styled from "@emotion/styled";

export const enum BUTTON_TYPE {
  MAIN = "main",
  LINK = "link",
}

const Button = ({
  text,
  type,
}: {
  text: string;
  type: BUTTON_TYPE;
}) => {
  return (
    <StyledButton type={type}>
      {text}
    </StyledButton>
  );
};

const getBorderColor = (type: BUTTON_TYPE): string => {
  if(type === BUTTON_TYPE.MAIN) {
    return "#abcabc";
  }
  else {
    return "#cbacba";
  }
};

const StyledButton = styled(BaseButton)<{
  type: BUTTON_TYPE;
}>`
  border: 1px solid ${({ type }) => getBorderColor(type)};
`;

export default Button;

Throws this error:

src/modules/Button/Button.tsx:18:6 - error TS2745: This JSX tag's 'children' prop 
expects type 'never' which requires multiple children, but only a single child was 
provided.

18     <StyledButton type={type}>
    ~~~~~~~~~~~~

src/modules/Button/Button.tsx:18:19 - error TS2322: Type 
'import("C:/ez/DS13/src/modules/Button/Button2").BUTTON_TYPE' is not assignable to type 
'never'.

18     <StyledButton type={type}>

What type change could fix the error?


Solution

  • The main issue is that your type prop of type BUTTON_TYPE conflicts with the type prop of <button> which has a type of "button" | "submit" | "reset". In the working example below, I have fixed it by using a different prop name of variant for that purpose on StyledButton. The Button type that is exported in your code still retains the type prop name, so usage would be the same as in your code.

    import * as React from "react";
    import BaseButton from "@mui/base/Button";
    import styled from "@emotion/styled";
    
    export const enum BUTTON_TYPE {
      MAIN = "main",
      LINK = "link"
    }
    const getBorderColor = (type: BUTTON_TYPE): string => {
      if (type === BUTTON_TYPE.MAIN) {
        return "#abcabc";
      } else {
        return "#cbacba";
      }
    };
    
    const StyledButton = styled(BaseButton, {
      shouldForwardProp: (propName) => propName !== "variant"
    })<{ variant: BUTTON_TYPE }>`
      border: 1px solid ${({ variant }) => getBorderColor(variant)};
    `;
    const Button = ({ text, type }: { text: string; type: BUTTON_TYPE }) => {
      return <StyledButton variant={type}>{text}</StyledButton>;
    };
    
    export default function Demo() {
      return (
        <>
          <Button type={BUTTON_TYPE.MAIN} text="Hello" />
          <Button type={BUTTON_TYPE.LINK} text="World" />
        </>
      );
    }
    

    Edit base Button customization