I am in the process of creating a generic component in typescript that we call GenericComponent for a library.
I want to achieve the following behavior from my library :
function GenericComponent<T>(props: GenericComponentProps<T>) {
// ...
return (
<GenericContext.Provider value={...}>
{/* ... */}
</GenericContext.Provider>
);
}
However, the issue is that the data provided in my context depends on the generic type of the component where it's being provided, T. So, how can I create my context? Because I can't do:
const GenericContext = createContext<GenericContextType<T>>(...)
I tried to create my context within the component, but I don't know if it's a best approach.
After development, using GenericComponent should looks like this :
type TheTypeT = ...
function App() {
// a state or something that we pass to the component
const [theTypeT, setTheTypeT] = useState<TheTypeT>(...);
return (
<GenericComponent
theTypeT={theTypeT}
/>
);
}
But I don't know where in my library I could create my context that depend on the type of theTypeT
Here, I present the approach I take, it's pretty clean, imho. Here's a Codesandbox link for all the code, down below, each file is linked individually as well.
First, I create a wrapper around the react's
createContextlike this -src/hooks/create-context.tsThen, to make the typings for different context types available, without having to import them manually, create a file
index.d.tsat project root level to house typings, and add your types here to use from, I'm showing a simple counter example using this -To make the types from
index.d.tsavailable in all the places, edittsconfig.jsonto add the./index.d.tspath in theincludefield -Now, on to creating our counter context, create a file
src/hooks/counter-context.tsxand use thecreateContexthook created to create a counter context -From this file, we export the
useCounterContexthook provided by thecreateContextand theCounterContextcomponent that provides access to the context.After that, use
CounterContextabove the component, whose children will be using the context. In my case, I use the context insrc/App.tsx, so we add theCounterContextinsrc/main.tsx, which uses<App />component as child -And then at last, we use the context in any child of the
<App />component, or the<App />component itself, like so -