You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 19:53:11