简体   繁体   中英

Typescript Conditional Object Keys: Prop A exists Prob B must exist

Background

I want to conditionally type keys in an object based on the existence of another key in that object.

Problem

I have an object that has some required keys and some optional. I do not know how to make it so one of the optional keys is contingent upon the other optional key being present. For instance,

interface User { 
  username: string;
  id: string;
  member?: boolean; 
  memberStatus?: string;
}

Now, let's say I have a list of users that I am mapping through and I want to show a button if the user is a member and make that button a specific color based on memberStatus .

return users.map(user => (
  if(user.member) { 
    //memberStatus here will cause an error because it maybe a string or undefined
    <button className={memberStatus === 'active' ? 'green' : 'yellow'}>Member Button</button>
  }
  return (
    <p>{user.username} is a user</p>
  )
))

What I Tried

I looked up extending interfaces and conditional typing. However, extending a Member interface from the User interface but that still leaves me with optional keys.

Question

Is it possible to create an interface like so

interface User { 
 username: string;
 id: string;
 member?: string;
 memberStatus: string; 
}

type UserOrMember = User.member ? User : Omit<User, 'memberStatus'>

apiUsers: UserOrMember = [...users]

Again, the goal is that memberStatus is only required if member is not undefined .

Is there anything I am missing with extending interfaces or generics that could be helpful?

You can try Tagged union types :

// declare types
interface BaseUser {
  username: string;
  id: string;
  member?: boolean;
}

interface User extends BaseUser {
  member?: false;
}

interface Member extends BaseUser {
  member: true;
  memberStatus: string;
}

type UserOrMember = User | Member;

// usage in component
declare const user: UserOrMember
console.log(user.member ? user.memberStatus : user.username)

Playground Link

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM