Search code examples
reactjstypescripttypescript-generics

Passing Generics to function component React Typescript


I was just wondering if there is a way of handling this with generics than using any for the following.

I am still trying to wrap my head around the types and generics, just wanted to stay clear of using any. Or would this be an acceptable use case of using any !

SlotRenderer.tsx

// Can this be done ? 
interface SlotAProps<T> {
    slotData : T[]
}

// Should I stick with
interface SlotAProps {
    slotData : any[]
}

const SlotRenderer = (props: SlotAProps) => {
    return (
        <div>
            <p>Renders slot</p>
            // for version 1 I could do, currently this throws an error
            <p>{props.slotData[0]?.validity}</p>
            // for version 2 I could do, currently this throws an error
            <p>{props.slotData[0]?.totalPrice}</p>
        </div>
    )
}

The available types are

interface SampleOne {
    id: number;
    name: string;
    validity: string;
    isVisible: boolean;
}

interface SampleTwo {
    id: number;
    required: true
    sampleString: string;
    totalPrice: number;
}

The execution would be

// Version 1

const Container = () => {
    return (
        <ComponentBase
            // Passes a component to the Base component
            slot={<SlotRenderer<SampleOne> slotData={[{ id: 1, name:'', validity:'', isVisible:'' }]} />} 
        />
    )
}

// Version 2

const ContainerTwo = () => {
    return (
        <ComponentBase
            // Passes a component to the Base component
            slot={<SlotRenderer<SampleTwo> slotData={[{ id: 1, required:true, sampleString:'', totalPrice:10 }]} />} 
        />
    )
}

Solution

  • The only thing you were missing is adding a type variable to the component function:

    const SlotRenderer = <T extends unknown>(props: SlotAProps<T>) => {
      // ...
    }
    

    So the reason you weren't able to do so before is that you correctly defined the generic props type and know of the syntax for using generic components in tsx, but were not aware that you'd need this extra type variable to forward it to the generic props type.

    The extends unknown in the above example is a hack to enable a type parameter in an arrow function in .tsx files, since otherwise the syntax is ambiguous with the opening tag of a component.

    You can find more tips for working with typescript+react in the React TypeScript Cheatsheet project.