I had read this question Generics error with forwardRef: Property 'ref' does not exist on type 'IntrinsicAttributes'
Here is my case:
import React from "react";
interface ThirdPartyComponentProps
extends React.ComponentPropsWithRef<"input"> {}
const ThirdPartyComponent: React.ComponentType<ThirdPartyComponentProps> =
React.forwardRef<HTMLInputElement, ThirdPartyComponentProps>(
(props: ThirdPartyComponentProps, ref) => {
return (
<div>
<input ref={ref} type="text" {...props} />
</div>
);
}
);
interface AppProps
extends React.ComponentPropsWithRef<typeof ThirdPartyComponent> {}
export const App = React.forwardRef((props: AppProps, ref) => {
return <ThirdPartyComponent ref={ref} {...props} />;
});
Got TS type error:
Type '((instance: unknown) => void) | MutableRefObject<unknown> | null' is not assignable to type '((instance: HTMLInputElement | null) => void) | RefObject<HTMLInputElement> | null | undefined'.
Type 'MutableRefObject<unknown>' is not assignable to type '((instance: HTMLInputElement | null) => void) | RefObject<HTMLInputElement> | null | undefined'.
Type 'MutableRefObject<unknown>' is not assignable to type 'RefObject<HTMLInputElement>'.
Types of property 'current' are incompatible.
Type 'unknown' is not assignable to type 'HTMLInputElement | null'.
Type 'unknown' is not assignable to type 'HTMLInputElement'.ts(2322)
index.d.ts(816, 46): The expected type comes from property 'ref' which is declared here on type 'IntrinsicAttributes & ThirdPartyComponentProps & { children?: ReactNode; }'
Since the ThirdPartyComponent
component is a component of a third-party library, I don't know which HTML element the forward ref is used on. It may be the root element or an internal element, such as the input
element in the example.
I know that the type of forwarding ref is HTMLInputELement
from the error, but this is the type of ref that I learned through an error.
How to declare or infer the type of ThirdPartyComponent
ref directly on the consumer side, that is, in the App
component.
What's the ref type for React.forwardRef<??, AppProps>
generic type.
TypeScript Playground
It requires a bit of typescript gymnastic.
Since ThirdPartyComponent
is a React.ComponentType<ThirdPartyComponentProps>
we should start from inferinf ComponentType
.
This is our first line:
T extends React.ComponentType<infer Ref>
Then we need to infer the props of ComponentType
, I mean these ThirdPartyComponentProps
props.
Ref extends React.DetailedHTMLProps<
React.InputHTMLAttributes<infer RefElement>,
any
>
RefElement
is the element we are looking for.
Whole code:
import React from "react";
interface ThirdPartyComponentProps
extends React.ComponentPropsWithRef<"input"> { }
const ThirdPartyComponent: React.ComponentType<ThirdPartyComponentProps> =
React.forwardRef<HTMLInputElement, React.ComponentPropsWithRef<"input">>(
(props: ThirdPartyComponentProps, ref) => {
return (
<div>
<input ref={ref} type="text" {...props} />
</div>
);
}
);
type InferHTMLElement<T> =
(T extends React.ComponentType<infer Ref>
? (Ref extends React.DetailedHTMLProps<React.InputHTMLAttributes<infer RefElement>, any>
? RefElement
: never
)
: never
)
{
// HTMLInputElement
type Test = InferHTMLElement<typeof ThirdPartyComponent>
}
interface AppProps
extends React.ComponentPropsWithRef<typeof ThirdPartyComponent> { }
export const App = React.forwardRef<InferHTMLElement<typeof ThirdPartyComponent>>((props: AppProps, ref) => {
return <ThirdPartyComponent ref={ref} {...props} />;
});
Playground
You can try to replace "input"
with "div"
and you will see that it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With