0

I'm using classnames to add many classes to a React component. In my button I want to have the opportunity to add a class to the component if I want to, it should be optional.

But I get a type error, see attached image enter image description here

How can I get rid of the error?

Button code

import classnames from "classnames";
import styles from "./button.module.css";

interface ButtonProps {
    children: JSX.Element;
    onClick: () => void;
    small?: boolean;
    className?: string;
}

function Button({ onClick, children, small, className }: ButtonProps) {
    return (
        <button
            className={classnames(styles.button, {
                [styles.small]: small,
                [className]: !!className,
            })}
            onClick={onClick}
        >
            {children}
        </button>
    );
}

export default Button;

and the error:

A computed property name must be of type 'string', 'number', 'symbol', or 'any'.ts(2464)

Or Assayag
  • 5,662
  • 13
  • 57
  • 93
Sanne Wintrén
  • 359
  • 1
  • 4
  • 12
  • You are casting it to a boolean with `!!`. Why? – Roberto Zvjerković Jan 08 '21 at 15:54
  • 1
    Since `className` prop is optional its type is `string | undefined` which conflicts with the typing of an object's property name. Either make `className` mandatory or change the code to only add the property when it's actually defined. – juliomalves Jan 08 '21 at 15:56
  • If `className` is not defined then you will end up with an object property like `{"undefined": false}` where the computed property name `undefined` has been coerced to a string. The TypeScript compiler assumes that's an error. If you *want* this to happen (unlikely) you should do `[String(className)]: !!className]`. If you *don't* want this to happen (likely) you should do something like a conditional spread – jcalz Jan 08 '21 at 16:03

1 Answers1

1

Your className is used as a property name even though it might be undefined. Note that an optional string is really a string | undefined. I would use object spread to accomplish conditionality.

The new argument to classnames function:

{
  [styles.small]: small,
  ...(typeof className === 'string' ?
    { [className]: true } :
    {}
  )
}
rwusana
  • 149
  • 4