React TS鉴权上下文开发:createContext报错修复咨询
React Typescript 鉴权上下文 createContext 报错解决方法
问题根源
在Typescript中,createContext必须明确指定上下文的类型,并且传入符合该类型的默认值——这和JS里可以空调用的逻辑不同,也是你之前报错的原因。
具体修正步骤
1. 定义上下文类型接口
先导入Supabase的User类型,然后定义包含所有鉴权方法和状态的接口,用TS的类型推导自动匹配Supabase方法的参数和返回值:
import { User } from '@supabase/supabase-js'; import { createContext, useContext, useState, ReactNode } from 'react'; // 定义鉴权上下文的完整类型 interface AuthContextType { currentUser: User | null | undefined; login: (email: string, password: string) => ReturnType<typeof supabase.auth.signInWithPassword>; signup: (email: string, password: string) => ReturnType<typeof supabase.auth.signUp>; logout: () => ReturnType<typeof supabase.auth.signOut>; recoverPassword: (email: string) => ReturnType<typeof supabase.auth.resetPasswordForEmail>; update: (data: Parameters<typeof supabase.auth.updateUser>[0]) => ReturnType<typeof supabase.auth.updateUser>; }
2. 给createContext传入合法默认值
按照上面定义的接口,传入结构一致的默认值(默认值的作用是满足TS类型检查,同时避免组件在Provider外调用useAuth时崩溃):
// 初始化上下文并传入默认值 const AuthContext = createContext<AuthContextType>({ currentUser: undefined, // 所有方法返回Supabase标准的空结构 login: async () => ({ data: null, error: null }), signup: async () => ({ data: null, error: null }), logout: async () => ({ error: null }), recoverPassword: async () => ({ error: null }), update: async () => ({ data: null, error: null }), });
3. 修正组件内的类型问题
- 把
AuthProvider的children类型从any改成ReactNode(React官方推荐的子组件类型) - 明确
useState的currentUser类型,避免TS隐式推断错误
完整修正后的代码
import { User } from '@supabase/supabase-js'; import { createContext, useContext, useState, ReactNode } from 'react'; // 注意导入你的supabase实例 import supabase from './your-supabase-instance-path'; interface AuthContextType { currentUser: User | null | undefined; login: (email: string, password: string) => ReturnType<typeof supabase.auth.signInWithPassword>; signup: (email: string, password: string) => ReturnType<typeof supabase.auth.signUp>; logout: () => ReturnType<typeof supabase.auth.signOut>; recoverPassword: (email: string) => ReturnType<typeof supabase.auth.resetPasswordForEmail>; update: (data: Parameters<typeof supabase.auth.updateUser>[0]) => ReturnType<typeof supabase.auth.updateUser>; } const AuthContext = createContext<AuthContextType>({ currentUser: undefined, login: async () => ({ data: null, error: null }), signup: async () => ({ data: null, error: null }), logout: async () => ({ error: null }), recoverPassword: async () => ({ error: null }), update: async () => ({ data: null, error: null }), }); export function useAuth() { return useContext(AuthContext); } export default function AuthProvider({ children }: { children: ReactNode }) { // 明确currentUser的类型 const [currentUser, setCurrentUser] = useState<User | null | undefined>(); function signup(email: string, password: string) { return supabase.auth.signUp({ email, password }); } function login(email: string, password: string) { return supabase.auth.signInWithPassword({ email, password }); } function logout() { return supabase.auth.signOut(); } function recoverPassword(email: string) { return supabase.auth.resetPasswordForEmail(email); } function update(data: Parameters<typeof supabase.auth.updateUser>[0]) { return supabase.auth.updateUser(data); } const value = { currentUser, login, signup, logout, recoverPassword, update }; return ( <AuthContext.Provider value={value}> {children} </AuthContext.Provider> ); }
额外说明
- 用
ReturnType和Parameters可以自动同步Supabase方法的类型,不用手动写复杂的返回值/参数类型,后续Supabase更新时类型也会自动适配 - 默认值里的异步方法返回空结构,是为了保证如果有人在
AuthProvider外部调用useAuth(虽然不推荐),不会直接抛出错误
内容的提问来源于stack exchange,提问作者IVOBOT
相关产品推荐
相关产品推荐

