使用Supabase认证结合React Toolkit Query时queryFn出现TypeScript类型错误
使用Supabase认证结合React Toolkit Query时queryFn出现TypeScript类型错误
看起来你遇到的核心问题是TypeScript类型不匹配,具体来说是自定义的响应类型和RTK Query要求的返回结构、Supabase实际返回的数据结构三者没对齐。我来一步步帮你拆解和解决:
错误根源分析
从报错信息能看出来几个关键点:
- 你定义的
SignupResponse接口和SupabasesignUp返回的data(包含user和session字段)完全没有交集,导致返回{ data }时类型冲突。 - RTK Query的
queryFn要求返回的QueryReturnValue结构中,data必须严格匹配你在mutation泛型里定义的类型,而你当前的返回值结构不符合这个要求。 - 你尝试用
AuthResponse时也踩了坑:Supabase的AuthResponse是包含data和error的整体结构,但RTK Query的mutation泛型第一个参数是成功时的data类型,不是整个响应对象,所以直接用会导致类型不兼容。
解决方案步骤
1. 修正类型定义,对齐Supabase返回结构
首先我们要明确成功和错误场景的类型,让它们既符合Supabase的返回格式,又满足RTK Query的要求:
// 先导入Supabase的内置类型,确保类型引用正确 import { User, Session, AuthError } from '@supabase/supabase-js'; // 定义成功响应的类型,完全对齐Supabase signUp返回的data结构 type SignupSuccessData = { user: User | null; session: Session | null; }; // 定义错误响应的类型,包含错误信息和状态码 type SignupError = { message: string; status: number; }; // 顺便修正你的Signup类型(之前写错了Schema名称) const SignupForm = z.object({ email: z.string().email({ message: "Please enter a valid email address." }), password: z .string() .min(6, { message: "Minimum 6 characters." }) // 你之前写的是2,这里应该是6? .max(50, { message: "Maximum 50 characters." }), confirmPassword: z.string().min(6).max(50), name: z.string().min(2, { message: "Name must be at least 2 characters." }), }); type Signup = z.infer<typeof SignupForm>; // 这里应该是SignupForm,不是SignupApi
2. 调整queryFn的返回逻辑,匹配RTK Query要求
RTK Query的queryFn返回值只能是两种结构:{ data: 成功类型 } 或者 { error: 错误类型 },我们要确保所有分支都严格符合这个规则:
signupWithCredentials: builder.mutation<SignupSuccessData, Signup>({ async queryFn({ email, password }) { const { data, error } = await supabase.auth.signUp({ email, password, }); // 处理邮箱已存在的特殊场景(Supabase返回的user.identities为空) if (data?.user?.identities?.length === 0) { return { error: { message: "Email already registered", status: 409, // 用409(冲突)比500(服务器错误)更符合HTTP语义 } as SignupError, }; } // 处理Supabase返回的其他错误 if (error) { return { error: { message: error.message, status: error.status ?? 500, // 给个默认值,避免status为undefined } as SignupError, }; } // 兜底处理:如果没有error但data为空的异常情况 if (!data) { return { error: { message: "Unexpected error occurred", status: 500, } as SignupError, }; } // 成功场景:返回符合SignupSuccessData类型的data return { data }; }, }),
额外提示
- 状态码尽量使用符合HTTP语义的数值,比如邮箱重复用409,参数错误用400,服务器错误用500,这样前端处理错误时更清晰。
- 如果不想自己定义类型,可以直接复用Supabase的
AuthResponse['data']作为成功类型,这样更省心:type SignupSuccessData = AuthResponse['data'];
备注:内容来源于stack exchange,提问作者Pratik
相关产品推荐
相关产品推荐

