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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 00:37:50