2

I'm struggling to get type checking in Typescript to work for a React component which uses forwardRef and has a ...rest property.

Example:

import React from 'react'

interface InputWithLabelProps {
  label: string,
  [rest: string]: unknown,
}

const InputWithLabel = React.forwardRef<HTMLInputElement, InputWithLabelProps>(
  ({ label, ...rest }, ref) => (
    <>
      <label htmlFor="field">{label}</label>
      <input id="field" ref={ref} {...rest} />
    </>
  ),
)

export default InputWithLabel

This will give component the following signature:

(alias) const InputWithLabel: React.ForwardRefExoticComponent<Pick<InputWithLabelProps, keyof InputWithLabelProps> & React.RefAttributes<HTMLInputElement>>
import InputWithLabel

This will not give correct type checking for example it's not necessary to provide label property which should be required. If I remove either forwardRef or the ...rest property it works, but that is not an option.

How can I use forwardRef on a component which has ...rest property and at the same time have type checking?

Andreas
  • 25
  • 1
  • 6

1 Answers1

1

Using [rest: string]: unknown you allow any string property to be passed to your input element which (for a reason I do not understand why) renders your other prop types useless. Assuming you want to type your component with a mandatory label and otherwise any props belonging to an <input>-element, you can extend this by using either:

interface InputWithLabelProps extends React.InputHTMLAttributes<HTMLInputElement> {
  label: string
}

or combining the types using:

type InputWithLabelProps = {
    label: string
} & React.HTMLProps<HTMLInputElement>
Dirk J. Faber
  • 4,360
  • 5
  • 20
  • 58
  • Correct me if I'm wrong but [rest: string]: unknown or [rest: string]: any allows me to pass any property of any type to component? https://thewebdev.info/2022/03/20/how-to-add-types-for-rest-props-in-react-and-typescript/ This is just a simplified example. What if passing the ...rest property to a composite component, not a HTMLInputElement? – Andreas Jun 22 '22 at 20:46
  • yes, you are correct. – Dirk J. Faber Jun 22 '22 at 20:52
  • The reason I wrote down "string property" is because the name (or key) of your property is a string (and always is using React). – Dirk J. Faber Jun 22 '22 at 20:53
  • Your suggestion actually makes sense to me now and it will work in my case. Thanx – Andreas Jun 22 '22 at 20:55
  • FYI: there also is a difference between a type `any` and `unknown`, see this question for more information on this matter: https://stackoverflow.com/questions/51439843/unknown-vs-any – Dirk J. Faber Jun 22 '22 at 20:56