A solution I was able to get working with the assistance of Copilot AI but tested and working by me in my application:
The Child Component: [receiving the ref]
Note the "as <TData, TOption>" at the end of the ChildComponent definition is the critical piece to make this work.
import { forwardRef, ForwardedRef } from 'react';
// Define the props interface with generics
interface ChildComponentProps<TData, TOption> {
data: TData[];
option?: TOption;
onSelect?: (item: TData) => void;
}
export const ChildComponent = forwardRef(
<TData, TOption>(
{
data,
option,
onSelect
}: ChildComponentProps<TData, TOption>,
ref: ForwardedRef<ComponentRef<TData>>
) => {
// Component implementation...
return <div>Component Content</div>;
}
) as <TData, TOption>(
props: ChildComponentProps<TData, TOption> & {
ref?: ForwardedRef<ComponentRef<TData>>;
}
) => JSX.Element;
The Parent Component usage of child: [passing in the ref]
interface User {
id: number;
name: string;
}
type Options = "small" | "large";
<ChildComponent<User, Options>
ref={componentRef}
data={users}
option="small"
onSelect={(user) => console.log(user.name)}
/>
The type for Parent Component's Ref is:
RefObject<any>
Which you can type as necessary, I didn't have my use case finalised to give you a well typed solution for that particular piece. If it is a generic Element type, use that. If it is something custom (special returned functions from Child) use that definition.
forwardRefand just have callers callStringInputdirectly, passing theforwardedRefprop. Note that generic components are unsound to begin with, so I wouldn't hope for full support for type checking their usage.