Home > other >  How to define type for createContext
How to define type for createContext

Time:10-07

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>
  );
}

CodePudding user response:

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>
  );
}

CodePudding user response:

Since you're passing state and the setter for the state, the type should be:

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

Dispatch<SetStateAction<IUser>> is the type of the setter, and if you want to know what exactly it is, here was an answer about that.


Also, {} is not needed here:

const [user, setUser] = useState<IUser>({});

This is fine since IUser has all its properties marked as optional.

Playground

  • Related