React with Typescript — Generics while using React.forwardRef

后端 未结 1 937
猫巷女王i
猫巷女王i 2020-12-31 06:11

I am trying to create a generic component where a user can pass the a custom OptionType to the component to get type checking all the way through. This componen

1条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-31 06:37

    Creating a generic component as output of React.forwardRef is not directly possible1 (see bottom for further info). There are some alternatives though - let's simplify your example a bit for illustration:

    type Option = {
        value: O;
        label: string;
    }
    type Props> = { options: T[] }
    
    const options = [
      { value: 1, label: "la1", flag: true }, 
      { value: 2, label: "la2", flag: false }
    ] // just some options data
    

    1. Cast it

    // Given input comp for React.forwardRef
    const FRefInputComp = (props: Props, ref: Ref) =>
        
    {props.options.map(o =>

    {o.label}

    )}
    // Cast the output const FRefOutputComp1 = React.forwardRef(FRefInputComp) as (p: Props & { ref?: Ref }) => ReactElement const Usage11 = () => // options has type { value: number; label: string; flag: boolean; }[] // , so we have made FRefOutputComp generic!

    This works, as the return type of forwardRef in principle is a plain function. We just need a generic function type shape. You could an extra type to make the assertion simpler:

    type ForwardRefFn = 

    (p: P & React.RefAttributes) => ReactElement | null // RefAttributes is built-in with ref and key props defined const Comp12 = React.forwardRef(FRefInputComp) as ForwardRefFn const Usage12 = () =>

    2. Wrap it

    const FRefOutputComp2 = React.forwardRef(FRefInputComp)
    // T is replaced by its constraint Option in FRefOutputComp2
    
    export const Wrapper = ({myRef, ...rest}:
        Props & {myRef: React.Ref}) => 
    
    const Usage2 = () => 
    

    3. Omit it (use custom ref prop)

    This one is my favorite - simplest alternative, a legitimate way in React and doesn't use forwardRef.

    const Comp3 = (props: Props & { myRef: Ref }) =>
        
    {props.options.map(o =>

    {o.label}

    )}
    const Usage3 = () =>

    1 The type declaration of React.forwardRef is:

    function forwardRef(render: ForwardRefRenderFunction): ...
    

    So it takes a generic component-like interface, whose type parameters T, P must be concrete. In other words: ForwardRefRenderFunction is not a generic function declaration, so higher order function type inference cannot propagate free type parameters on to the calling function React.forwardRef.


    Playground

    0 讨论(0)
提交回复
热议问题