Search code examples
reactjstypescriptreact-contextreact-typescript

How to define type for createContext


Trying to learn typescript by migrating one of my old project to typescript.
Having trouble in defining type for the following Context-hook inside a React application.

const authContext = createContext<IUser | {}[]>([{}, () => {}]);

As you can see, I have used <IUser | {}[]> where,

interface IUser {
    name?: string;
    token?: string;
}

I am using the context like this:

function CheckAuth({ children }) {
  const [user] = useAuth();
  return (!user.name ? (<Navigate to='/login' />)
    : children
  );
}

where useAuth() is:

export function useAuth() {
  return useContext(authContext);
}

I am getting an error in CheckAuth() saying Property 'name' doesn't exist on type {}.

More info -

This is how the context is being declared in the React app.

function ProvideAuth({ children }) {
  const [user, setUser] = useState<IUser | {}>({});
  return (
    <authContext.Provider value={auth}>
      {children}
    </authContext.Provider>
  );
}

Solution

  • Here's a complete example based on the code in your question. I've included comments to explain in the code below:

    TS Playground

    import {
      default as React,
      createContext,
      type Dispatch,
      type ReactElement,
      type ReactNode,
      type SetStateAction,
      useContext,
      useState,
    } from 'react';
    
    import { Navigate } from 'react-router-dom';
    
    interface IUser {
      name?: string;
      token?: string;
    }
    
    // This tuple (array) type is what's returned by `useState<IUser>`:
    type IUserState = [
      IUser,
      Dispatch<SetStateAction<IUser>>,
    ];
    
    // Here's how to initialize the context:
    const authContext = createContext<IUserState>([{}, () => {}]);
    
    function useAuth () {
      return useContext(authContext);
    }
    
    // React function components which accept children
    // need a `children` prop type like this:
    type ChildrenProps = { children?: ReactNode };
    
    function CheckAuth ({ children }: ChildrenProps): ReactNode {
      const [user] = useAuth();
      return (user.name ? children : (<Navigate to='/login' />));
    }
    
    function ProvideAuth ({ children }: ChildrenProps): ReactElement {
      // Get the tuple (array) returned by `useState`:
      const userState = useState<IUser>({});
    
      // And assign it to the context provider `value` prop:
      return (
        <authContext.Provider value={userState}>
          {children}
        </authContext.Provider>
      );
    }