I am using context for Auth in my simple typescript app.
My context declaration is in the file
AuthProvider.tsx
, which looks like:
import React, { createContext, useState } from 'react';
import auth from '@react-native-firebase/auth';
export interface IAuth {
user,
setUser,
login,
register,
logout
}
export const AuthContext = createContext<IAuth | null>(null);
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider
value={{
user: user,
setUser: setUser,
login: async (email, password) => {
try {
await auth().signInWithEmailAndPassword(email, password);
} catch (e) {
console.log(e);
}
},
register: async (email, password) => {
try {
await auth().createUserWithEmailAndPassword(email, password);
} catch (e) {
console.log(e);
}
},
logout: async () => {
try {
await auth().signOut();
} catch (e) {
console.log(e);
}
},
}}>
{children}
</AuthContext.Provider>
);
};
This is how I am using it elsewhere:
const { user, setUser } = useContext(AuthContext);
But Typescript throws 2 errors on this lien:
What can I do to bypass it?
Right here, you have said that contents of your AuthContext
can be either an IAuth
object or it can be null
.
export const AuthContext = createContext<IAuth | null>(null);
You cannot destructure the value of useContext(AuthContext)
as if it were an object because you have not verified that it is an actually an IAuth
and not null
.
There are many ways to address this.
One approach is that you can still allow for the context value to be null
, but we have to check before using it. This works and is easy to implement. We can exit the component early by returning null if the values don't exist. But you must make sure that you exit only after all other hooks have been called or else you'll get a "violated the rules of hooks" error.
export const Consumer = () => {
const context = useContext(AuthContext);
if ( ! context ) {
return null;
}
const { user, setUser } = context;
return (
<div/>
)
}
Another approach is that we allow for an empty or incomplete object instead of null
. This allows us to destructure, but we are just moving the errors down the chain because those two value that we destructured user
and setUser
might have the expected values or might be undefined
.
export const AuthContext = createContext<Partial<IAuth>>({});
const { user, setUser } = useContext(AuthContext);
A more verbose approach is to create a default value for the context which fulfills the IAuth
interface by using dummy methods. These functions should be callable so that won't produce errors but they don't do anything.
const defaultValue: IAuth = {
setUser: () => console.error("attempting to use AuthContext outside of a valid provider"),
/*... */
}
export const AuthContext = createContext<IAuth>(defaultValue);
Does your interface really look like what you've posted, or did you just remove the values for the sake of the question? An interface needs to define the type associated with each key, not just list the keys.
I guess you can cast it to IAuth with
const { user, setUser } = useContext(AuthContext) as IAuth
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With