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