Reputation: 2081
I have the following interfaces
declared
export interface User {
...
first: string;
...
}
export interface UserDataState {
credentials: User | {};
..
}
In my react component, I want to be able to access the first
in the UserDataState
like this:
const userData = useSelector((state: RootState) => state.user.credentials);
Welcome, { userData.first }
However I'm getting this error
Property 'first' does not exist on type '{} | User'.
So I tried the following:
let userFirst = '';
if (userData.hasOwnProperty('first')) {
userFirst = userData.first;
}
...
return ( <span>{userFirst}</span>)
and..
return ( {userData && userData.first && (<span>{userData.first}</span>)})
I don't want to make the user first optional and I need to be able to return an empty object to as the credentials. This is very much annoying.
Upvotes: 1
Views: 638
Reputation: 3069
I suggest that you use optional chaning.
For example, in your case, I would do the following:
export interface UserDataState {
credentials: User | undefined;
}
To access first
from crendentials
from state
(suppose state
is nullable), instead of doing:
state && state.credentials && state.credentials.first
You just need to use the optional chaining operator ?.
state?.credentials?.first
By doing this you won't compromise the type safety of your codebase with explicit casting, for example casting to any
.
This idiom is pretty standard with Typescript 3.7 and above.
Upvotes: 1
Reputation: 2485
You can do something like this, so basically what you are doing is enforcing the type that it is going to be a User
type:
const userData = useSelector((state: RootState) => state.user.credentials) as User;
Upvotes: 0
Reputation: 2081
I got it working with
const user = useSelector((state: RootState) => state.user.credentials);
const userData: any = user;
// or this works to
import { User as UserType } from '../types';
const userData: { first?: UserType['first'] } = user;
Not sure if this is best practice though, if anyone has a better method would love to hear it
Upvotes: 0