reactjstypescript

TypeScript with React's useContext? property does not exist


Trying to use TypeScript with React's useContext. Thought I had it figured out but get an error stating that the props do not exist when I destructure the custom hook.

Here's my custom hook - no TypeScript errors from what I see

type AppContext = {
  handleLogin: HandleLogin;
};

type HandleLogin = (email: string, password: string) => void;

const AuthContext = createContext<AppContext | null>(null);

export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
  const [user, setUser] = useState(null);

  const router = useRouter();

  // Handle login
  const handleLogin: HandleLogin = async (email: string, password: string) => {
    const userData = await login(email, password);
    setUser(userData);
  };

  return (
    <AuthContext.Provider value={{ handleLogin }}>
      {children}
    </AuthContext.Provider>
  );
};

But when I destructure the hook like so...

  const { handleLogin } = useAuth();

I get the following error - * Property 'handleLogin' does not exist on type 'AppContext | null'.*

I get the same error if I include another value or function within the context's value but run into the same error. Really not sure what I'm missing.


Solution

  • You're assigning the initial value of context as null, so you need to make sure the context is not null when you're restructuring. Or you can tell typescript that context will always be AppContext.

    const AuthContext = createContext<AppContext>({} as AppContext);
    

    It's type-safe because the value will be set on the Provider when your component uses the context.

    UPDATE: The below is probably a better solution.

    const AuthContext = createContext<AppContext|null>(null);
    
    export default function useAuthContext() {
      const context = useContext(AuthContext);
      if (!context) throw Error("useAuthContext can only be used inside an AuthProvider");
      return context;
    }
    

    This gives you type safety without any conversions, plus a runtime check that the hook is used properly. Note that it depends on the context's initial value being null.