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;
}
CodePudding user response:
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;
}
}
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;
}
}