htmlangulartypescriptwebstorm

Can't change an *ngFor to a @for. Its @for(commune of communes) is rejected, telling that Commune[] needs an iterator. But Commune is an interface


I have a Commune interface generated by an OpenAPI generator:

/** Une commune du Code Officiel Géographique */
export interface Commune { 
    /** Code de la commune */
    codeCommune: string;

    /** Code du département */
    codeDepartement: string;

    /** Nom du département */
    nomDepartement: string;
[...]
}

A CommunesComponent gathers by a REST call some communes: a Commune[] array.

export class CommunesComponent implements OnInit {
  /** Année du Code Officiel Géographique. */
  @Input()
  anneeCOG: number;

  /** Locale du tri des communes */
  @Input()
  locale: string = 'fr_FR';

  /** Liste des communes ordonnées par locale */
  communes: Commune[];

  /** Codes communes avec leur commune associée. */
  communesMap: Map<string, Commune> = new Map<string, Commune>();

  /** Code commune sélectionné. */
  codeCommune: string = null;

  /** Commune sélectionnée (objet). */
  communeSelectionnee: Commune = null;

  /** Libellé final de la commune sélectionnée. */
  libelleCommuneSelectionnee: string;
[...]

  /**
   * Réaction à l'initialisation du composant :
   * Lire les communes triées par locale, et sous forme de Map indexée par codeCommune.
   */
  ngOnInit(): void {
    // Vérification du paramètre d'appel (année)
    if (this.anneeCOG < 2019 || this.anneeCOG >= 2100) {
      const message = 'L\'année du code officiel géographique ' + this.anneeCOG + ' n\'est pas valide : choissez-là à partir de 2019.';
      console.log(message);
      return;
    }

    this.cogService.obtenirCommunesTriParLocale(this.anneeCOG, false, this.locale).subscribe(data => {
      this.communes = data;

      this.communes.forEach(commune => {
        this.communesMap.set(commune.codeCommune, commune);
      });
    });
  }
[...]

Where the service is called by one of these prototypes, also generated by OpenAPI:

public obtenirCommunesTriParLocale(anneeCOG: number, locale: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: '*/*'}): Observable<Array<Commune>>;
public obtenirCommunesTriParLocale(anneeCOG: number, locale: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: '*/*'}): Observable<HttpResponse<Array<Commune>>>;
public obtenirCommunesTriParLocale(anneeCOG: number, locale: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: '*/*'}): Observable<HttpEvent<Array<Commune>>>;
public obtenirCommunesTriParLocale(anneeCOG: number, locale: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: '*/*'}): Observable<any> {
   [...]
}

And the data it returns, if I put a breakpoint just at the forEach to see its content, is:

enter image description here

Until now, I was using it in an *ngFor, without troubles:

<datalist id="communesCOG">
  <option *ngFor="let commune of communes" [value]="commune.codeCommune">{{commune.nomCommune}} ({{commune.nomDepartement}})</option>
</datalist>

that creates this combobox:
enter image description here

Being in Angular 20 now, I'd like to put it in a @for statement instead:

<datalist id="communesCOG">
  @for (commune of communes; track commune.codeCommune) {
     <option [value]="commune.codeCommune">{{commune.nomCommune}} ({{commune.nomDepartement}})</option>
  }
</datalist>

But I'm receiving the error that Type Commune[] must have a [Symbol.iterator]() method that returns an iterator.

How can I put an iterator, and where, if it's what I have to do?

I don't understand why:

If I say: *ngFor="let A of B" and @for (C of D ; track C.id)


Solution

  • I think the problem is not a Typescript nor Angular error.


    It has more to do with a false trigger from IntelliJ or Webstorm. You can try solving this by updating the Angular Language Service to the latest version.

    If the above does not help, then raise a ticket with webstorm or IntelliJ official support, for them to get back on why this false positive happens.


    An alternative will be to try the alternative way to type an array. So instead of Commune[] try Array<Commune> which might solve your problem.