TypeScript下React Context Hook报错:类型'{}'不存在属性'setUser'
React Context + TypeScript:解决
setUser类型错误 我在为登录页面配置React Context Hook(TypeScript开发)时遇到类型声明问题,使用setUser时弹出错误:Property 'setUser' does not exist on type '{}'。
原Context Hook代码
import { createContext, ReactNode, useEffect, useState } from "react" interface Props { children?: ReactNode } export const UserContext = createContext({}) export function UserContextProvider({children}: Props) { const [user, setUser] = useState(null) return ( <UserContext.Provider value={{user, setUser}}> {children} </UserContext.Provider> ) }
原登录页面代码
import { Link, Navigate } from "react-router-dom" import axios from 'axios' import { UserContext } from "../UserContext" const Login = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [redirect, setRedirect] = useState(false) const {setUser} = useContext(UserContext) async function handleLogin(e: any) { e.preventDefault() try { const userInfo = await axios.post('/auth/login', {email, password}) setUser(userInfo) alert('Login') setRedirect(true) } catch (e) { alert('Login failed') } } if(redirect){ return <Navigate to={'/'} /> } return ( <div> <div> <h1>Login</h1> <form onSubmit={handleLogin}> <input type="email" placeholder="your@email.com" value={email} onChange={e => setEmail(e.target.value)}/> <input type="password" placeholder="password" value={password} onChange={e => setPassword(e.target.value)}/> <button>Login</button> <div> Don't have an account? <Link to="/auth/register"> Sign Up</Link> </div> </form> </div> </div> ) } export default Login
解决方案
核心问题是未给UserContext定义明确的TypeScript类型,初始值{}被推断为空对象,导致TypeScript无法识别setUser的存在。以下是修复步骤:
1. 完善Context文件的类型声明
import { createContext, ReactNode, useState, Dispatch, SetStateAction } from "react" // 定义用户信息类型,根据后端返回字段调整 interface User { id?: string; email?: string; // 其他用户字段... } // 定义Context的完整类型 interface UserContextType { user: User | null; setUser: Dispatch<SetStateAction<User | null>>; } interface Props { children?: ReactNode } // 用定义好的类型初始化Context,提供符合类型的默认值 export const UserContext = createContext<UserContextType>({ user: null, setUser: () => {} // 空函数作为默认值,避免未包裹Provider时报错 }) export function UserContextProvider({children}: Props) { // 给useState显式指定类型 const [user, setUser] = useState<User | null>(null) return ( <UserContext.Provider value={{user, setUser}}> {children} </UserContext.Provider> ) }
2. 修正登录组件的细节问题
import { Link, Navigate } from "react-router-dom" import axios from 'axios' import { UserContext } from "../UserContext" // 补上useContext的导入 import { useState, useContext } from "react" // 复用User类型或直接声明 interface User { id?: string; email?: string; } const Login = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [redirect, setRedirect] = useState(false) const {setUser} = useContext(UserContext) // 替换e: any为React.FormEvent,避免类型滥用 async function handleLogin(e: React.FormEvent) { e.preventDefault() try { // 给axios.post指定返回类型,确保数据类型正确 const userInfo = await axios.post<User>('/auth/login', {email, password}) // 注意:axios返回的用户数据在data字段中 setUser(userInfo.data) alert('Login') setRedirect(true) } catch (e) { alert('Login failed') } } if(redirect){ return <Navigate to={'/'} /> } return ( <div> <div> <h1>Login</h1> <form onSubmit={handleLogin}> <input type="email" placeholder="your@email.com" value={email} onChange={e => setEmail(e.target.value)}/> <input type="password" placeholder="password" value={password} onChange={e => setPassword(e.target.value)}/> <button>Login</button> <div> Don't have an account? <Link to="/auth/register"> Sign Up</Link> </div> </form> </div> </div> ) } export default Login
关键修复点
- 给
UserContext显式指定类型,让TypeScript识别user和setUser的存在 - 初始化Context时提供符合类型的默认值,避免未包裹Provider时的运行时错误
- 给
useState和axios请求指定明确类型,消除隐式any - 修正axios数据获取逻辑,正确取
data字段作为用户信息
内容的提问来源于stack exchange,提问作者Nichelle
相关产品推荐
相关产品推荐

