Core of my question
const FinalComponent<GenericType extends 'a' | 'b'> = is invalid tsx syntax.
// The 1st line here is invalid tsx syntax
const FinalComponent<InvalidGenericType extends 'a' | 'b'> =
forwardRef<HTMLParagraphElement, PropsWithStandardRef<InvalidGenericType>>(({ value }, ref) => {
return <Component forwardedRef={ref} value={value} />
}) as ComponentType<InvalidGenericType>
Intended usage of the component:
const ExampleUsage = () => <FinalComponent<'b'> value="b" />
How do I make a generic type in this situation?
Additional context
For additional context, here is the rest of the code:
import { Ref, forwardRef } from 'react'
// These are the base props for the component.
// In terms of usage, these are the props that I care about.
interface Props<GenericType extends 'a' | 'b'> {
value: GenericType
}
// Adding forwardedRef to the props to define what props are usable inside the component
interface PropsWithForwardRef<GenericType extends 'a' | 'b'> extends Props<GenericType> {
forwardedRef: Ref<HTMLParagraphElement | null>
}
// Adding standard ref to the props to define what props the component can accept from outside
interface PropsWithStandardRef<GenericType extends 'a' | 'b'> extends Props<GenericType> {
ref?: Ref<HTMLParagraphElement | null>
}
// forwardRef is interfering with the inheritance of the generic types.
// This is a stand in for the expected return type of the component.
type ComponentType<GenericType extends 'a' | 'b'> = (props: PropsWithStandardRef<GenericType>) => JSX.Element
// The core component code
function CoreComponent<GenericType extends 'a' | 'b'> ({ value, forwardedRef }:PropsWithForwardRef<GenericType>):JSX.Element {
return <p ref={forwardedRef}>{value}</p>
}
// !!!!!!!!!!! IMPORTANT BIT !!!!!!!!!!!!
// This is where my problem is, I need to be able to pass a dynamic generic type into PropsWithStandardRef and ComponentType.
// I'm not sure how to do that though because `const FinalComponent<InvalidGenericType extends 'a' | 'b'> = forwardRef()` is invalid
const FinalComponent<InvalidGenericType extends 'a' | 'b'> = forwardRef<HTMLParagraphElement, PropsWithStandardRef<InvalidGenericType>>(({ value }, ref) => {
return <CoreComponent forwardedRef={ref} value={value} />
// I need the `as ComponentType<InvalidGenericType>` bit because the inferred type that comes out of forwardRef
// is making TS lose the generic types information
}) as ComponentType<InvalidGenericType>
// This is the end goal of how I want to be able to use this component
// I want to be able to pass a generic type into the component without TS complaining
const ExampleUsage = () => <FinalComponent<'b'> value="b" />
PS. I recognize that this example is a bit contrived, it is for the sake of simplifying my real world problem which features a far more complex component.
Similar but different question
This is different to React Typescript - dynamic types
In that question, it doesn't require passing the type information into the variable, more just changing what the type is based on what values the user provides.
I need the end use of the component to be able to pass a type into it.