Jamie
Jamie

Reputation: 2081

Object key optional with typescript — but being able to call it

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

Answers (3)

Wong Jia Hau
Wong Jia Hau

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

fayeed
fayeed

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

Jamie
Jamie

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

Related Questions