Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use React.forwardRef with a ref type based on a prop

Say I have the following component:

interface Props {
  as: keyof HTMLElementTagNameMap
  // ... other props
}

const A = React.forwardRef<any, Props>((props, ref) => {
   // ... implementation
})

This component will render an HTMl element based on the as prop, and the caller can pass in a ref to attach to the element. Currently, I'm using any for the type of the ref, but ideally, I'd want that to be the actual HTMLElement subtype based on the as prop that's being passed in. How can I do that? I can likely get the actual tag type from HTMLElementTagNameMap, but I'm just not sure how to write that into the function signature.

like image 729
bigblind Avatar asked Nov 02 '25 07:11

bigblind


1 Answers

What you're asking is not possible (although there exists a workaround).

Why it is not possible

You need generics to "bind" together the two type parameters provided to forwardRef. Consider the following code:

interface Props<T extends keyof HTMLElementTagNameMap> {
  as: T;
  // ... other props
}

const A = React.forwardRef<HTMLElementTagNameMap[T], Props<T>>(
  (props, ref) => {
    return null;
  }
);

The declaration of T parameter is missing at the component level. There is nowhere you can put such declaration. This is a limitation of React.forwardRef.

Workaround

As a workaround, you can ditch forwardRef and add the ref to your Props interface:

interface Props<T extends keyof HTMLElementTagNameMap> {
  as: T;
  theRef: React.Ref<HTMLElementTagNameMap[T]>
  // ... other props
}

function A<T extends keyof HTMLElementTagNameMap>(props: Props<T>) {
  const { as, theRef, /*...*/ } = props;
  return null;
}

Example in the TypeScript playground.

like image 109
Backslash36 Avatar answered Nov 05 '25 00:11

Backslash36