Тип объединения: нельзя использовать второй необязательный тип в forloop - PullRequest
0 голосов
/ 14 мая 2018

У меня есть массив, через который я хочу выполнить цикл, но у меня проблема из-за типа объединения. Мой вопрос заключается в том, что я пропустил в следующем коде, поэтому код Visual Studio не видит, что у меня есть второй необязательный тип для этого конкретного массива?

class Menu {
  // name of the menu
 name: string;
  // list of the ingredients in this menu
  // or a list of submenu with its ingredients
 list: string[] | Menu[];
 hasSubList?: boolean;
}

...
menu: Menu[];

ngOnInit() {
  this.loadMenu();
}
ngAfterContentInit() {
  this.print();
}
loadMenu(): void {
  this.menu = [
   {
     name: "toast" 
     list: [
      "slide of bread",
     ],
   },
   {
     name: "Crumble eggs on taste",
     hasSubList: true;
     list: [
      {
        name: "Eggs",
        list: [
         {
           "Eggs",
           "pepper",
           "a pinch of salt",
          }
         ],
       },
       {
        name: "Toast",
        list: [
          "a slide of bread"
         ],
        },
       ],
   },
 ];
}

this print(): void {
  for(let i=0; i<this.menu.length;i++){
    let item = this.menu[i];
    console.log(item.name);
    for(let j=0; i<item.list.length; j++){
      let list = item.list[j];
      if(item.hasSubList) {
         // HERE
         // console intellsense says 
         // "property 'list' does not exist on type 'string | Menu'
         // "property 'list' does not exist on type 'string'
        for(let k=0; k< list.list.length; k++}(
          console.log(list.list[k]);
        }
      } else {
       console.log(list);
      }
}

Просто чтобы повторить сообщение о том, что показывал intellsense;

"property 'list' does not exist on type 'string | Menu'
"property 'list' does not exist on type 'string'

Почему он не проверил меню? потому что «список» существует как тип «Меню»

Ответы [ 3 ]

0 голосов
/ 14 мая 2018

Как упомянуто @jacobm, компилятор не может узнать, основываясь на hasSubList , что является фактическим типом типа объединения.

Вы должны использовать способ различения, понятный компилятору.1 Способ сделать это - проверить тип самого элемента, и тогда вам даже не понадобится свойство hasSubList .

например

for(let i=0; i<this.menu.length;i++){
    let item = this.menu[i];

    for(let j=0; i<item.list.length; j++){
        let list = item.list[j];

        // typeof operator can help discriminate the union type
        if(typeof item !== 'string') {
            for(let k=0; k< list.list.length; k++}(
                console.log(list.list[k]);
            }
        } else {
            console.log(list);
        }
    }
}

Вот еще один пример использования циклов for..of вместо циклов for.Это может быть стилистическим предпочтением, но я бы порекомендовал использовать их в тех случаях, когда вы не используете индекс цикла, поскольку они более лаконичны и IMO более читабельны.

for (let item of menu) {
    for (let list of item.list) {
        if(item !== 'string') {
            for(let childItem of list.list) {
                console.log(childItem);
            }
        } else {
            console.log(list);
        }
    }
}
0 голосов
/ 14 мая 2018

Сообщение вызвано Typescript не может сказать, какой тип вы собираетесь использовать, так как вы назначаете его как string | Menu[]. Использование приведения является одним из способов решения этой проблемы.

for (let j = 0; i < item.list.length; j++) {
    if (item.hasSubList) {
      let list = item.list[j] as Menu; // use 'as'     
      for (let k = 0; k < list.list.length; k++) {
        console.log(list[k]);
      }
    } else {
      let list = item.list[j];  
      console.log(list);
    }
  }
0 голосов
/ 14 мая 2018

Поскольку list[j] имеет тип string | Menu, код, который его использует, должен иметь возможность обрабатывать или строк или меню, он не может обрабатывать только одно или другое. Я думаю, что вы полагаетесь на знание того, что если hasSubList верно, то list - это всегда список меню. Если это то, что вы имеете в виду, тогда вы можете привести item к меню (list as Menu), хотя в общем случае лучше избегать таких приведений, поскольку они ограничивают то, насколько средство проверки типов может отлавливать истинные ошибки в вашем коде.

...