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.
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
.