出现TS错误:类型'IAuth |属性'user'不存在。空值'

时间:2020-10-23 16:14:40

标签: reactjs typescript react-native

我在简单的打字稿应用程序中使用Auth上下文。 我的上下文声明在文件中 AuthProvider.tsx,如下所示:

import React, { createContext, useState } from 'react';
import auth from '@react-native-firebase/auth';

export interface IAuth {
    user,
    setUser,
    login,
    register,
    logout
}

export const AuthContext = createContext<IAuth | null>(null);

export const AuthProvider = ({ children }) => {
    const [user, setUser] = useState(null);

    return (
        <AuthContext.Provider
            value={{
                user: user,
                setUser: setUser,
                login: async (email, password) => {
                    try {
                        await auth().signInWithEmailAndPassword(email, password);
                    } catch (e) {
                        console.log(e);
                    }
                },
                register: async (email, password) => {
                    try {
                        await auth().createUserWithEmailAndPassword(email, password);
                    } catch (e) {
                        console.log(e);
                    }
                },
                logout: async () => {
                    try {
                        await auth().signOut();
                    } catch (e) {
                        console.log(e);
                    }
                },
            }}>
            {children}
        </AuthContext.Provider>
    );
};

这就是我在其他地方使用它的方式:

  const { user, setUser } = useContext(AuthContext);

但是Typescript在此留置权上抛出2个错误:

  1. “ IAuth |类型”上不存在属性“用户”空”
  2. 类型“ IAuth |属性”上不存在属性“ setUser”空”

我该怎么做才能绕过它?

4 个答案:

答案 0 :(得分:1)

创建上下文时,您需要提供一个默认值,但是您使用空值创建它。

在您的情况下,您可能正在使用useContextHook从另一个组件访问它

请考虑这种情况,如果您直接访问它而不提供提供者级别的值,并且从上下文访问用户或其他字段,它将不会在那里。因此它抱怨说这些值不存在,要解决此问题,您必须提供如下所示的默认值(您也应在IAuth中设置其他字段)。

export const AuthContext = createContext<IAuth | null>({user:{},setUser:()=>{}});

答案 1 :(得分:0)

我想您可以将其转换为IAuth const { user, setUser } = useContext(AuthContext) as IAuth

答案 2 :(得分:0)

推断是正确的,上下文可能为null。进行空检查:

const ctx = useContext(AuthContext);
if(ctx !== null) {
  const { user, setUser } = ctx;
  // ...
}

答案 3 :(得分:0)

在这里,您已经说过AuthContext的内容可以是IAuth对象,也可以是null

export const AuthContext = createContext<IAuth | null>(null);

不能将useContext(AuthContext)的值看成一个对象,因为您尚未验证它实际上是IAuth而不是null

有很多解决方法。

一种方法是您仍然可以将上下文值设置为null,但是我们必须在使用它之前进行检查。这有效并且易于实现。如果值不存在,我们可以通过返回null来提前退出组件。但是,您必须确保仅在调用所有其他钩子之后退出,否则将收到“违反了钩子规则”错误。

export const Consumer = () => {
   const context = useContext(AuthContext);
   if ( ! context ) {
     return null;
   }
   const { user, setUser } = context;

   return (
     <div/>
   )
}

另一种方法是我们允许一个空的或不完整的对象,而不是null。这使我们能够进行结构调整,但是我们只是将错误向下移动,因为我们对usersetUser进行结构调整的两个值可能具有预期值,或者可能是undefined

export const AuthContext = createContext<Partial<IAuth>>({});
const { user, setUser } = useContext(AuthContext);

更详细的方法是使用伪方法为满足IAuth接口的上下文创建默认值。这些函数应该是可调用的,这样就不会产生错误,但是它们什么也不做。

const defaultValue: IAuth = {
  setUser: () => console.error("attempting to use AuthContext outside of a valid provider"),
  /*... */
}

export const AuthContext = createContext<IAuth>(defaultValue);

您的界面确实看起来像您发布的内容,还是只是出于问题的考虑而删除了这些值?接口需要定义与每个键关联的类型,而不仅仅是列出键。