首页 > 解决方案 > 类型 {} 中缺少,但类型“”和“”中是必需的不能分配给字符串索引类型“”错误

问题描述

我想要实现的主要是将登录用户的电子邮件地址dict作为键传递,获取其对应的令牌值,并使用它作为查询参数进行 API 调用。用户的电子邮件地址来自用户登录时返回的用户数据,我只需要他/她的电子邮件地址。这userInfo就是定义接口的地方。在下面的代码片段中,编译器通过说“类型‘{}’中缺少属性‘电子邮件’但在类型‘userInfo’中是必需的”来引发错误。我通过添加“?”解决了这个问题 email在接口中变量的末尾。然后它给了我另一个错误:“'string | undefined'类型的属性'email'不可分配给字符串索引类型'string'。”email是对象的唯一属性,不应未定义。由于上述错误,我完全被困在这一点上。如果你能给我一个解决这个问题的建议,那将不胜感激。

//tokenDict.tsx
export const tokenDict: { [email: string]: string } = {
  "user1@example.com": "sample_token1",
  "user2@example.com": "sample_token2",
};



//HomeScreen.tsx
interface userInfo {
  email: string; //email vs email?
  [key: string]: string; 
}
const HomeScreen: React.FC = () => {
  const user: userInfo = useGlobalState("user"); //user object returned from login process is stored in user state in Redux.
  const userEmail: string = user.email;
  const token = tokenDict[userEmail];

标签: reactjstypescript

解决方案


In terms of what is required vs. optional, some of that depends on your app:

  • Do you always have a user returned from useGlobalState("user");, or is this component sometimes loaded when no user has logged in?
  • Does every user object have an email property?
  • Does every email address have a token?

When you have cases where a variable might be empty or undefined, you need to check if it exists or not. If it doesn't exist you would want to throw an Error or show a different component. For example you might want to render a login form if there is no logged in user.

Based on the wording of your error "Property 'email' is missing in type '{}' but required in type 'userInfo'" I'm thinking that you are returning an empty object in your hook when there is no logged-in user. I would recommend that you return undefined instead. Either you have a valid userInfo object, or there is no user.

I don't have all of your code (like the useGlobalState hook) so this is just a stub of how you would handle this. Let's assume that the answers to the second and third bullet points are "yes" and the only check we need to do is whether or not we have a user.

All users will have an email. (rather than an index signature [key: string]: string; I would define the specific keys and values).

interface UserInfo {
  email: string;
}

Some sort of hook accesses the current user:

const useCurrentUser = (): UserInfo | undefined => {
  // implementation
}

The portions of your app which require credentials can take those credentials as props:

interface AuthenticatedProps {
    user: UserInfo;
    token: string;
}

const Authenticated: React.FC<AuthenticatedProps> = ({user, token}) => {
    return (
        <div>Some Logged In Stuff</div>
    )
}

You create some component to show when there is not a valid user:

const AccessRestricted: React.FC = () => {
    return (
        <div>You must be logged-in to view this content.</div>
    )
}

Now in your HomeScreen, we look for a user and render either the Authenticated or the AccessRestricted component based on whether a user was found.

There are a few ways to deal with the token:

  • You can assert that the token definitely exists using token as string (this suppresses typescript errors, but could cause runtime errors if it actually doesn't exist).
  • You can check if it exists and show an error message if it doesn't.
  • You can replace undefined with an empty string (token || ''), which will pass the typescript checks, assuming that further down the chain you will deal with invalid tokens at some point.
const HomeScreen: React.FC = () => {
  const user = useCurrentUser();
  if ( ! user ) {
      return (
          <AccessRestricted />
      )
  }
  const userEmail: string = user.email;
  const token = tokenDict[userEmail];
  return (
      <Authenticated
        token={token || ''}
        user={user}
      />
  )
}

推荐阅读