Home > Enterprise >  Use React.forwardRef with a ref type based on a prop
Use React.forwardRef with a ref type based on a prop

Time:12-12

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.

CodePudding user response:

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.

CodePudding user response:

Access by the key of prop

const A = React.forwardRef<Props['as'], Props>((props, ref) => {
  • Related