简体   繁体   中英

Property does not exist on union interface type

I have an object that contains an array of team members, the smallest object-type implements either interface Member or interface Manager . Manager-objects can contain other interface Member objects. Each member/manager has their own key: string .

As you can see from the code, I am trying to implement a function setProfession(key, profession) which sets a profession: string property for a certain member/manager based on their personal key: string .

There is this error within my setProfession function:

Property 'members' does not exist on type 'Member | Manager'.

I don't understand the error, because I have put a safe guard on the line just before the line where the error is. Yet it still throws an error, even though interface Manager obviously contains the members property: Error printscreen

interface Member {
  key: string;
  name: string;
  profession: string;
}

interface Manager {
  key: string;
  name: string;
  profession: string;
  members: Array<Member>
}

interface Team {
  members: Array<Member | Manager>
}

const TEAM: Team = {
  members: [
    {
      key: 'RodneyMcKay1',
      name: 'Rodney McKay',
      profession: 'Scientist'
    }, {
      key: 'JohnShephard1',
      name: 'John Shephard',
      profession: 'Soldier',
      members: [
        {
          key: 'TeylaEmmagan1',
          name: 'Teyla Emmagan',
          profession: 'Soldier'
        }, {
          key: 'RononDex1',
          name: 'Ronon Dex',
          profession: 'Soldier'
        }
      ]
    }
  ]
};

const isManager = (member: Member | Manager): member is Manager => {
  return member.hasOwnProperty('members');
}

const setProfession = (key: string, profession: string): boolean => {
  for (let i = 0; i < TEAM.members.length; i++) {
    if (isManager(TEAM.members[i])) {    // SAFE GUARD 
      for (let j = 0; j < TEAM.members[i].members.length; j++) {    // ERROR
         if (TEAM.members[i].members[j].key === key) {    // ERROR
           TEAM.members[i].members[j].profession = profession;    // ERROR
           return true;
         }
      }
    } else if (TEAM.members[i].key === key) {
      TEAM.members[i].profession = profession;
      return true;
    }
  }

  return false;
}

Typescript can't quite track all the drill-ins there. You can help it out by assigning the tested value to a variable:

  for (let i = 0; i < TEAM.members.length; i++) {
    const person = TEAM.members[i]
    
    if (isManager(person)) {
      for (let j = 0; j < person.members.length; j++) {
         if (person.members[j].key === key) {
           person.members[j].profession = profession;
           return true;
         }
      }
    } else if (person.key === key) {
      person.profession = profession;
      return true;
    }
  }

See playground


This gets a lot easier if you use iteration instead of indexed loops. Then you get this variable created as part of that loop for free. And your code is easier to read and understand, as an added benefit.

  for (const person of TEAM.members) {
    if (isManager(person)) {
      for (const member of person.members) {
         if (member.key === key) {
           member.profession = profession;
           return true;
         }
      }
    } else if (person.key === key) {
      person.profession = profession;
      return true;
    }
  }

See playground

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