React中使用自定义声明渲染差异化UI的User类型错误解决
解决自定义声明赋值时的TypeScript类型错误
问题根源是onAuthStateChanged返回的是Firebase官方的User类型实例,你自定义的User类型和它不兼容,不能直接给Firebase User实例添加admin属性。以下是具体解决方法:
1. 定义兼容的应用用户类型
导入Firebase的User类型,扩展出包含admin字段的自定义应用用户类型,避免类型冲突:
import { User as FirebaseUser } from "firebase/auth"; // 扩展Firebase用户类型,添加admin字段 type AppUser = FirebaseUser & { admin: boolean; };
注意:移除你原来自定义User类型里的
password字段,Firebase不会返回用户密码,这个字段没有意义。
2. 修正AuthContext和Reducer的类型
更新上下文和 reducer 的类型定义,使用新的AppUser:
export type Dispatch = (action: AuthAction) => void; // 明确状态类型 type AuthState = { user: AppUser | null; authIsReady: boolean; }; // 明确action类型 type AuthAction = | { type: "LOGIN"; payload: AppUser } | { type: "LOGOUT" } | { type: "AUTH_IS_READY"; payload: AppUser | null }; export const AuthContext = createContext< { dispatch: Dispatch; user: AppUser | null } | undefined >(undefined); export const authReducer = (state: AuthState, action: AuthAction) => { switch (action.type) { case "LOGIN": return { ...state, user: action.payload }; case "LOGOUT": return { ...state, user: null }; case "AUTH_IS_READY": return { ...state, user: action.payload, authIsReady: true }; default: return state; } };
3. 调整AuthContextProvider中的逻辑
不要直接修改Firebase User实例,而是创建新对象合并属性,并确保拿到admin字段后再分发状态:
export const AuthContextProvider: React.FunctionComponent<IProps> = ({ children, }) => { // 使用明确的初始状态类型 const [state, dispatch] = useReducer(authReducer, { user: null, authIsReady: false, } as AuthState); useEffect(() => { const unsub = onAuthStateChanged(auth, async (firebaseUser) => { if (!firebaseUser) { dispatch({ type: "AUTH_IS_READY", payload: null }); unsub(); return; } // 等待获取IdToken结果 const idTokenResult = await firebaseUser.getIdTokenResult(); // 创建新的应用用户对象,合并Firebase用户属性和admin字段 const appUser = { ...firebaseUser, admin: idTokenResult.claims.admin ?? false // 处理admin为undefined的情况 } as AppUser; // 拿到admin字段后再分发状态 dispatch({ type: "AUTH_IS_READY", payload: appUser }); unsub(); }); }, []); return ( <AuthContext.Provider value={{ ...state, dispatch }}> {children} </AuthContext.Provider> ); };
关键说明
- 永远不要直接修改Firebase返回的User实例,通过对象展开创建新对象来添加自定义字段,避免类型冲突和实例污染。
- 使用
async/await替代then,让代码更清晰,确保在获取到自定义声明后再更新状态,避免UI拿到不完整的用户数据。 - 用
?? false处理admin字段可能为undefined的情况,保证类型安全。
内容的提问来源于stack exchange,提问作者JosineD58
相关产品推荐
相关产品推荐

