Home > Net >  Using typescript generics in Reactjs function components
Using typescript generics in Reactjs function components

Time:11-17

I have the next component in my react application:

import "./styles.css";

type InpuType = "input" | "textarea";

interface IContainer {
  name: string;
  placeholder: string;
  as: InpuType;
}

const Container = ({
  name,
  placeholder,
  as,
  ...rest
}: IContainer &
  (
    | React.TextareaHTMLAttributes<HTMLTextAreaElement>
    | React.InputHTMLAttributes<HTMLInputElement>
  )) => {
  const Comp = as || "input";
  return <Comp name={name} placeholder={placeholder} {...rest} />;
};

export default function App() {
  return (
    <div className="App">
      <Container name="hi" as="textarea" placeholder="start" />
    </div>
  );
}

The ...rest are all the default props that could be added for a textarea or input.
I have a typescript issue here <Comp name={name} ..., hovering over the component i get this message:

Type '{ autoComplete?: string | undefined; autoFocus?: boolean | undefined; cols?: number | undefined; dirName?: string | undefined; disabled?: boolean | undefined; form?: string | undefined; ... 261 more ...; placeholder: string; } | { ...; }' is not assignable to type 'IntrinsicAttributes & ClassAttributes<HTMLInputElement> & InputHTMLAttributes<HTMLInputElement> & ClassAttributes<...> & TextareaHTMLAttributes<...>'.

and i am not sure how to get rid of that.
Question: Why the issue appear and how to solve it?
demo:https://codesandbox.io/s/react-typescript-forked-z6dk4i?file=/src/App.tsx:379-396

CodePudding user response:

Instead of throwing all the native props using rest ({...rest}) maybe it would be better to just differentiate the props between textarea and input.

interface IContainer {
  name: string;
  placeholder: string;
  textareaProps?: React.TextareaHTMLAttributes<HTMLTextAreaElement>;
  inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
}

const Container = ({
  name,
  placeholder,
  textareaProps,
  inputProps,
}: IContainer) => {
  if (inputProps) {
    return <input {...inputProps} name={name} placeholder={placeholder} />;
  }

  return <textarea {...textareaProps} name={name} placeholder={placeholder} />;
};

https://codesandbox.io/s/react-typescript-forked-j9kgh2?file=/src/App.tsx:51-523

CodePudding user response:

you should create a function and create the inputs based on what you pass to it

import "./styles.css";

type InpuType = "input" | "textarea";
interface IComp {
  name: string;
  placeholder: string;
  as: InpuType;
  rest?: any;
}
const Comp = ({ as, name, placeholder, ...rest }: IComp) => {
  switch (as) {
    case "input":
      return <input name={name} placeholder={placeholder} {...rest} />;
    case "textarea":
      return <textarea name={name} placeholder={placeholder} {...rest} />;
  }
};
interface IContainer {
  name: string;
  placeholder: string;
  as: InpuType;
}

const Container = ({
  name,
  placeholder,
  as,
  ...rest
}: IContainer &
  (
    | React.TextareaHTMLAttributes<HTMLTextAreaElement>
    | React.InputHTMLAttributes<HTMLInputElement>
  )) => {
  return <Comp as={as} name={name} placeholder={placeholder} {...rest} />;
};

export default function App() {
  return (
    <div className="App">
      <Container name="hi" as="textarea" placeholder="start" />
    </div>
  );
}
  • Related