React createContext issue in Typescript?

Solution 1:

It appears defaultValue value for React.createContext is expected to be of type:

interface IContextProps {
  state: IState;
  dispatch: ({type}:{type:string}) => void;
}

Once Context object is created for this type, for example like this:

export const AdminStore = React.createContext({} as IContextProps);

Provider React component should no longer complain about the error.

Here is the list of changes:

admin-store.tsx

import React, { useReducer } from "react";
import { initialState, IState, reducer } from "./reducer";


interface IContextProps {
  state: IState;
  dispatch: ({type}:{type:string}) => void;
}


export const AdminStore = React.createContext({} as IContextProps);

export function AdminStoreProvider(props: any) {
  const [state, dispatch] = useReducer(reducer, initialState);

  const value = { state, dispatch };
  return (
    <AdminStore.Provider value={value}>{props.children}</AdminStore.Provider>
  );
}

Solution 2:

I had a fun time with this so I figured I'd share what I came up with.

The SidebarProps represent the context's state. Everything else, besides the reducer actions, can essentially be used as is.

Here is a nice article explaining the exact same workaround (Not in TypeScript) : Mixing Hooks and Context Api

import React, { createContext, Dispatch, Reducer, useContext, useReducer } from 'react';

interface Actions {
    type: string;
    value: any;
}

interface SidebarProps {
    show: boolean;
    content: JSX.Element | null;
}

interface SidebarProviderProps {
    reducer: Reducer<SidebarProps, Actions>;
    initState: SidebarProps;
}

interface InitContextProps {
    state: SidebarProps;
    dispatch: Dispatch<Actions>;
}

export const SidebarContext = createContext({} as InitContextProps);
export const SidebarProvider: React.FC<SidebarProviderProps> = ({ reducer, initState, children }) => {
    const [state, dispatch] = useReducer(reducer, initState);
    const value = { state, dispatch };
    return (
        <SidebarContext.Provider value={value}>
            {children}
        </SidebarContext.Provider>
    );
};
export const useSidebar = () => useContext(SidebarContext);

const SidebarController: React.FC = ({ children }) => {
    const initState: SidebarProps = {
        show: false,
        content: null
    };

    const reducer: Reducer<SidebarProps, Actions> = (state, action) => {
        switch (action.type) {
            case 'setShow':
                return {
                    ...state,
                    show: action.value
                };

            case 'setContent':
                return {
                    ...state,
                    content: action.value
                };

            default:
                return state;
        }
    };

    return (
        <SidebarProvider reducer={reducer} initState={initState}>
            {children}
        </SidebarProvider>
    );
};

export default SidebarController;