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) => {