Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React/Typescript forwardRef types for an element which returns either an input or textArea

I'm trying to create a generic text input component for our application using react and typescript. I want it to be able to either be an input element or a textarea element based on a given prop. So it looks somewhat like this:

import {TextArea, Input} from 'ourComponentLibrary'

export const Component = forwardRef((props, ref) => {
  const Element = props.type === 'textArea' ? TextArea : Input

  return (
    <Element ref={ref} />
  )
})

This code works fine. However, when trying to incorporate types it becomes a little dicey. The ref type should be either HTMLInputElement or HTMLTextAreaElement based on the passed type prop. In my head, it would look something like this:

interface Props {
  ...
}

export const Component = forwardRef<
  HTMLInputElement | HTMLTextAreaElement,
  Props
>((props, ref) => {
  ...
});

However I know this isn't exactly what I need. Hence, the error: Type 'HTMLInputElement' is missing the following properties from type 'HTMLTextAreaElement': cols, rows, textLength, wrap

In summary, I want the types to align so that if the type prop is textArea then the ref type should be HTMLTextAreaElement, and if the type prop is input then the ref type should be HTMLInputAreaElement

Any advice?

Thanks.

like image 527
picklechips Avatar asked Sep 18 '20 23:09

picklechips


People also ask

What does forwardRef return?

React forwardRef is a method that allows parent components pass down (i.e., “forward”) refs to their children. Using forwardRef in React gives the child component a reference to a DOM element created by its parent component. This then allows the child to read and modify that element anywhere it is being used.

Is React forwardRef a hoc?

forwardRef() which means we have to apply the HOC before React.

Is forwardRef a hook?

The forwardRef hooks allows React users to pass refs to child components. The ref can be created and referenced with useRef or createRef and then passed in a parent component. Using forwardRef instead of useRef is useful when a ref needs to be accessed in a parent component.


1 Answers

I know I'm really late to answer this, but this is how I solved this problem. Maybe this will help someone else someday.

type InputElement = 'input' | 'textarea'

export type InputProps<E extends InputElement> = {
    multiline: E extends 'textarea' ? true : false
    /* rest of props */
}

const Component = React.forwardRef(function Component<E extends InputElement>(
    props: InputProps<E>,
    ref: React.Ref<HTMLElementTagNameMap[E] | null>,
) {
like image 168
Keith Murgic Avatar answered Sep 21 '22 17:09

Keith Murgic