React Contexts In Typescript

Josh Tardioli
2 min readJul 31, 2022

In the past, using React contexts with typescript was a frustrating experience for me. In the hopes that others can avoid that same frustration I have created this guide. The article will go over how to set up a standard context using typescript, and afterwards will explain how to set up a slightly more complex context which uses a reducer.

Part 1: Standard Context:

import { createContext, Dispatch, ReactNode, SetStateAction, useContext, useState } from 'react';type StateContextInterface = {state: string;setState: Dispatch<SetStateAction<string>>;};export const StateContext = createContext<StateContextInterface>(undefined!);export const StateProvider = ({ children }: { children: ReactNode }) => {const [state, setState] = useState<string>('');const value: StateContextInterface = { state, setState };return <StateContext.Provider value={value}>{children}</StateContext.Provider>;};export const useStateValue: () => StateContextInterface = () => {const stateContext = useContext(StateContext);if (stateContext === null) {throw new Error('useState() can only be used inside of <StateProvider />, please declare it at a higher level.');}return stateContext;};

Note: Here the state is typed as a string, however that could be changed to any value depending on your needs

Common problems

Focus on line 8. Many people would type the createContext as

StateContextInterface | undefined

In the past I’ve had problems with types not being compatible due to the undefined so I don’t recommend it. instead add an exclamation mark as shown.

Part 2: Reducer Context

import {createContext, Dispatch, ReactNode, Reducer, useContext, useReducer,} from "react";import { Action } from "../reducers/reducer";export interface State {example: string;}export const StateContext = createContext<[State, Dispatch<Action>]>(undefined!);export const StateProvider = ({reducer,children,}: {reducer: Reducer<State, Action>;children: ReactNode;}) => {const initialState = {example: "",};return (<StateContext.Provider value={useReducer(reducer, initialState)}>{children}</StateContext.Provider>);};export const useStateValue = () => useContext(StateContext);

Here the imported type Action on line 9 is the type of action for the reducer (second argument in reducer function). Again the state type in just an example and can be changed to suite your needs.

Congrats for making it to the end of the article. If you want save this article so you can copy the two code templates whenever you need to make a new context.

--

--