Skip to content

Compiler reports the variable $last inside the @for block as number when it is mapped into the Input/Output binding #52730

@nyannyacha

Description

@nyannyacha

Which @angular/* package(s) are the source of the bug?

core

Is this a regression?

Yes

Description

In @for block, passing $last variable into input/output binding for referring from the component, the compiler complains due to parameter type mismatch error.

app.component.html

<div>
  <!-- This works as always -->
  <div *ngFor="let banner of [1,2,3,4]; index as idx; last as isLast" (click)="onClick(isLast)">ngFor: {{ idx }}</div>

  <!-- Not work, tsc reports a type error in the binding position -->
  @for (banner of [1,2,3,4]; track banner; let idx = $index, isLast = $last) {
    <div (click)="onClick(isLast)">for block: {{ idx }}</div>
    <app-meow [meow]="isLast" />
  }
</div>

app.component.ts

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';

import { MeowComponent } from './meow.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, MeowComponent],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  protected onClick(last: boolean) {
    console.log(last);
  }
}

meow.component.ts

import { Component, Input } from "@angular/core";

@Component({
    standalone: true,
    selector: "app-meow",
    template: `
        <span>meow: {{ meow }}</span>
    `
})
export class MeowComponent {
    @Input({ required : true }) meow: boolean = false;
}

Output

[ERROR] NG5: Argument of type 'number' is not assignable to parameter of type 'boolean'. [plugin angular-compiler]

    src/app/app.component.html:5:26:
      5 │     <div (click)="onClick(isLast)">for block: {{ idx }}</div>
        ╵                           ~~~~~~

  Error occurs in the template of component AppComponent.

    src/app/app.component.ts:10:15:
      10 │   templateUrl: './app.component.html',
         ╵                ~~~~~~~~~~~~~~~~~~~~~~


✘ [ERROR] NG2: Type 'number' is not assignable to type 'boolean'. [plugin angular-compiler]

    src/app/app.component.html:6:15:
      6 │     <app-meow [meow]="isLast" />
        ╵                ~~~~

  Error occurs in the template of component AppComponent.

    src/app/app.component.ts:10:15:
      10 │   templateUrl: './app.component.html',
         ╵                ~~~~~~~~~~~~~~~~~~~~~~


Application bundle generation failed. [0.769 seconds]

When I capture the type check block, I can see the variables related to bindings are inferred as number.

import * as i0 from './app.component';
import * as i1 from '@angular/common';
import * as i2 from '@angular/core';
import * as i3 from './meow.component';


const _ctor1: <T = any, U extends i2.NgIterable<T> = i2.NgIterable<T>>(init: Pick<i1.NgForOf<T, U>, "ngForOf" | "ngForTrackBy" | "ngForTemplate">) => i1.NgForOf<T, U> = null!;

/*tcb1*/
function _tcb1(this: i0.AppComponent) { if (true) {
    this. /*D:ignore*/ /*T:COMPCOMP*/;
    var _t1 = document.createElement("div") /*0,5*/;
    var _t2 /*T:DIR*/ /*40,134*/ = _ctor1({ "ngForOf": ([1 /*68,69*/, 2 /*70,71*/, 3 /*72,73*/, 4 /*74,75*/] /*67,76*/) /*64,78*/, "ngForTrackBy": null as any, "ngForTemplate": null as any }) /*D:ignore*/;
    _t2.ngForOf /*64,66*/ = ([1 /*68,69*/, 2 /*70,71*/, 3 /*72,73*/, 4 /*74,75*/] /*67,76*/) /*64,78*/;
    var _t3: any = null!;
    if (i1.NgForOf.ngTemplateContextGuard(_t2, _t3) /*40,156*/) {
        var _t4 /*57,63*/ = _t3.$implicit /*53,64*/;
        var _t5 /*87,90*/ = (_t3.index /*78,83*/) /*78,92*/;
        var _t6 /*100,106*/ = (_t3.last /*92,96*/) /*92,106*/;
        var _t7 = document.createElement("div") /*40,134*/;
        _t7.addEventListener /*109,114*/("click", ($event /*T:EP*/): any => { if (i1.NgForOf.ngTemplateContextGuard(_t2, _t3) /*40,156*/)
            (this).onClick /*117,124*/(_t6 /*125,131*/) /*117,132*/; }) /*108,133*/;
        "" + (_t5 /*144,147*/);
    }
    for (const banner of [1 /*247,248*/, 2 /*249,250*/, 3 /*251,252*/, 4 /*253,254*/] /*246,255*/!) {
        var _t8 /*236,255*/ = banner;
        var _t9 /*271,303*/: number = null!;
        var _t10 /*271,303*/: number = null!;
        var _t11 /*306,306*/: number = null!;
        var _t12 /*306,306*/: number = null!;
        var _t13 /*306,306*/: number = null!;
        var _t14 /*306,306*/: number = null!;
        var _t15 = document.createElement("div") /*311,342*/;
        _t15.addEventListener /*317,322*/("click", ($event /*T:EP*/): any => { (this).onClick /*325,332*/(_t10 /*333,339*/) /*325,340*/; }) /*316,341*/;
        "" + (_t9 /*356,359*/);
        var _t16 = document.createElement("app-meow") /*373,401*/;
        var _t17: i3.MeowComponent /*T:DIR*/ /*373,401*/ = null!;
        _t17.meow /*384,388*/ = (_t10 /*391,397*/) /*383,398*/;
        _t8 /*263,269*/;
    }
} }

export const IS_A_MODULE = true;

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

No response

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 17.0.0
Node: 18.18.2
Package Manager: npm 9.8.1
OS: linux x64

Angular: 17.0.1
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, platform-server
... router, service-worker

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1700.0
@angular-devkit/build-angular   17.0.0
@angular-devkit/core            17.0.0
@angular-devkit/schematics      17.0.0
@angular/cdk                    17.0.0
@angular/cli                    17.0.0
@angular/ssr                    17.0.0
@schematics/angular             17.0.0
rxjs                            7.8.1
typescript                      5.2.2
zone.js                         0.14.2

Anything else?

2

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions