1

Once I started to use Typescript in React I notice one thing I don't like which is to the need to declare every props to a component. Before this we can use {...props} but now I have to declare in interface every single native props like ref, placeholder, defaultValue etc.

interface InputProps {
  customProp: boolean;
  props: any;
}

const Input = ({ customProp, placeholder, ...props }: InputProps) => { 
  //warning 
  return <input type="text" {...props} />;
};

https://codesandbox.io/s/distracted-burnell-vlt3i?file=/src/App.tsx

I want to enjoy the old day where I only need to declare non-native prop in the interface, possible? the native props has been passed via {...props}

2
  • Hmm.. Yup that is expected. So what is your question regarding that? Commented Jun 16, 2020 at 3:39
  • @wentjun updated my question, see last line.. Commented Jun 16, 2020 at 3:40

3 Answers 3

2
import * as React from "react";
import "./styles.css";

interface InputProps {
  customProp: boolean;
  // props: any; // I think it doesn't need to you.
  [key:string]: any;
}

const Input = ({ customProp, placeholder, ...props }: InputProps) => {
  return <input type="text" {...props} />;
};

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>

      <Input hello="hello" customProp={false} placeholder={"name"} />
    </div>
  );
}

You can enjoy your old day with [key:string]: any.

But, I don't want to recommend to use [key:string]: any.

because it makes no meaning with typescript.

and, In my opinion, If you get stressed with typescript, you can use js instead.

Sign up to request clarification or add additional context in comments.

Comments

1

I want to enjoy the old day where I only need to declare non-native prop in the interface, possible?

Yes, it's possible. Typescript allows interfaces to extend from others, so you can define your interface to have all the things that input elements expect, plus your custom prop:

export interface ExampleProps extends React.HTMLProps<HTMLInputElement> {
  customProp: boolean;
}

const Example: React.FC<ExampleProps> = ({ customProp, placeholder, ...rest }) => {
  const { t } = useTranslation();
  return <input type="text" {...rest} />;
};

With this definition, it's legal for me to try to render the following:

const Thing: FC = () => {
  return <Example placeholder="foo" customProp={true} defaultValue="3" />;
};

But typescript will point out if, for example, i fail to pass in custom prop, or if i pass in an object for the placholder.

2 Comments

this is the answer!
By the way, you did explicitly mention ref in your question, but refs will not be forwarded along by this kind of code (neither in javascript, nor in typescript). If that's something you need, look into React.forwardRef (reactjs.org/docs/forwarding-refs.html)
1

If you are working with TypeScript, the best practice would be to strictly define the interfaces/type aliases of your props for each component. For your case of the Input component, the correct interface would be

interface InputProps {
  customProp: boolean;
  placeholder: string;
  // add other props below
}

That being said, interfaces and type aliases can be exported, shared, and extended, thus this will reduce the amount of repeated code. For instance,

interface OtherInputProps extends InputProps {
  value: string;
}

Of course, you can do something like [key:string]: any, but that would totally defeat the purpose of using TypeScript, as you are essentially ignoring the typechecking capabilities of TypeScript. In that case, t will be less verbose, to revert back to JavaScript.


Edit: Just realised that OP is trying to extend the input props with additional props. In that case, the correct base type to use would be `React.InputHTMLAttributes:

export interface InputProps extends React.InputHTMLAttributes< HTMLInputElement> {
  customProp: boolean;
}

or

type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
  customProp: boolean;
}

3 Comments

every prop? how does that even make sense? imagine I have ref={ref} placeholder={placeholder} value={value} and I have to declare every single of this native props where I assume it can be passed through {...props}
You can still use {...props} in TypeScript, but you will have to define the required types on the target component.
Oh, I think I read your question wrongly. Just realised you are asking for the native html input props :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.