0

I am getting a Typescript error for props.className below:

type PropsType = {
  handleChange?: Function;
  props?: { [key: string]: any };
};

export default function Search({ handleChange, ...props }: PropsType) {
  return (
    <div className={`search-bar flex middle ${props.className ?? ""}`}>
      <div className="search-icon flex middle">
        <svg>
          <use href="#search-icon" />
        </svg>
      </div>
      <input placeholder="Search" size={1} />
    </div>
  );
}

I get the error "Property 'className' does not exist on type '{ props?: { [key: string]: any; } | undefined; }'" but that's to be expected since I'm spreading the rest of the parameters in, right? I just want to add the className to the element if it's there (in props).

For additional info, I'm converting this Component to Typescript and am using Next.js 13 (experimental).

  • 3
    `type PropsType = { handleChange?: Function; [key: string]: any };` – Jerryh001 Mar 13 '23 at 14:48
  • 1
    This seems like a typo; you've defined `PropsType` as having a *property named `props`*, but then you're spreading the rest of `PropsType` into an object named `props`... so one could expect `props.props` to exist, not `props.className`. What does a value of `PropsType` actually look like? – jcalz Mar 13 '23 at 14:50
  • Well I added `props` to `PropsType` because I wasn't sure what to do. If I remove it I get the error: `Property 'className' does not exist on type '{}'.` `PropsType` is only explicitly looking for a `handleChange` function and the rest of the properties will just be added to the component (which I haven't done yet). – Julian Brooks Mar 13 '23 at 14:59
  • So then you presumably want what @Jerryh001 suggested. Does that work for you? If so maybe Jerryh001 will write up an answer post. If not what is the issue? – jcalz Mar 13 '23 at 15:02
  • 1
    @Jerryh001 that did it. I actually just tried it after reading jcalz response and then saw your comment. Thank you both. Can you mark a comment as the solution? – Julian Brooks Mar 13 '23 at 15:04
  • OK I just post it with both the comment and another solution – Jerryh001 Mar 13 '23 at 16:25

2 Answers2

1

To pass any props to a component, the string signature should be defined as the following:

type PropsType = {
    handleChange?: Function;
    [key: string]: any
};

This makes you code work but not suggest because it disable all type checks.


And in my opinion, className is a known property so it should be explicitly defined:

type PropsType = {
    handleChange?: Function;
    className?: string;
};
Jerryh001
  • 766
  • 2
  • 11
  • thanks! I did end up switching it to the second solution. But I definitely needed the first solution. Appreciate your help. – Julian Brooks Mar 13 '23 at 18:18
0

To utilize the full potential of Typescript and brings a static type system to Javascript you should create a props type with the elements written out. this will tell typescript what types you expect to be passed to the component. Otherwise you lose out on some of the benefits that typescript brings, since defining [key: string]: any essentially removes the static types, since you can now input everything.

type PropsType = {
  handleChange?: Function;
  propsClassName: string;
};

function Search({ handleChange, propsClassName }: PropsType) {
  return (
    <div className={`search-bar flex middle ${propsClassName ?? ""}`}>
      <div className="search-icon flex middle">
        <svg>
          <use href="#search-icon" />
        </svg>
      </div>
      <input placeholder="Search" size={1} />
    </div>
  );
}
Nils Kähler
  • 2,645
  • 1
  • 21
  • 26
  • I appreciate the feedback. However, the only property I want to explicitly type is the `handleChange` prop. The rest of the props could be anything and they'll be added directly to the wrapping element. I intentionally want `...props` to be 'anything else'. – Julian Brooks Mar 13 '23 at 15:27