2
votes

What I am trying to achieve is primarily to pass the login user's email address to dict as a key, get its corresponding token value, and use it to make an API call as a query parameter. The user's email address comes from returned user data when a user logs in, and I just need his/her email address from it. That's where the userInfo interface is defined. In the following code snippet, the compiler throws an error by saying "Property 'email' is missing in type '{}' but required in type 'userInfo'." I fixed this issue by adding '?' at the end of the email variable in the interface. Then it gives me another error: "Property 'email' of type 'string | undefined' is not assignable to string index type 'string'." I understand this issue because email is the only property of the object and it should not be undefined. Due to those errors above, I have been totally stuck at this point. If you could give me a suggestion to resolve this issue, that would be greatly appreciated.

//tokenDict.tsx
export const tokenDict: { [email: string]: string } = {
  "[email protected]": "sample_token1",
  "[email protected]": "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];
1

1 Answers

0
votes

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}
      />
  )
}