Skip to content

Template check does not fail for ngModel and readonly Signals #67188

@rainerhahnekamp

Description

@rainerhahnekamp

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

Don't known / other, forms

Is this a regression?

Yes

Description

Description

There is a gap in the Angular template type checker (ngtsc) regarding two-way binding with Signals.
When the child's input type is any, the compiler appears to skip validation of the Signal's "writability."

Specifically, providing a read-only Signal (e.g., from a computed()) to a two-way binding [(ngModel)] should result in a compilation error, as the binding requires a WritableSignal to perform updates. Currently, if the model's inner type is any, this error is suppressed.

This missing check introduced an issue in the NgRx SignalStore: ngrx/platform#4959

Reproduction Details

Code Example:

import { Component, Directive, model, computed, signal } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

@Directive({
  selector: '[stringModel]',
})
export class StringModel {
  myModel = model.required<string>();
}

@Directive({
  selector: '[anyModel]',
})
export class AnyModel {
  // The 'any' type here suppresses the check for WritableSignal requirements
  anyModel = model.required<any>();
}

@Component({
  selector: 'app-root',
  imports: [FormsModule, StringModel, AnyModel],
  template: `
    <input [(ngModel)]="value" name="ngModel" /> 
    <!-- this would fail: <input [(myModel)]="value" name="stringModel" /> -->
    <input [(anyModel)]="value" name="anyModel" />
  `,
})
export class Main {
  value = signal(1).asReadonly();
}

bootstrapApplication(Main);

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/github-eb8jh42v?file=src%2Fmain.ts

Please provide the exception or error you saw

That's the point. The exception isn't shown.

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

Angular CLI       : 21.1.4
Angular           : 21.1.5
Node.js           : 20.19.1
Package Manager   : npm 10.8.2
Operating System  : linux x64

┌───────────────────────────────────┬───────────────────┬───────────────────┐
│ Package                           │ Installed Version │ Requested Version │
├───────────────────────────────────┼───────────────────┼───────────────────┤
│ @angular/animations               │ 21.1.5            │ ^21.0.6           │
│ @angular/build                    │ 21.1.4            │ ^21.0.4           │
│ @angular/cli                      │ 21.1.4            │ ^21.0.4           │
│ @angular/common                   │ 21.1.5            │ ^21.0.6           │
│ @angular/compiler                 │ 21.1.5            │ ^21.0.6           │
│ @angular/compiler-cli             │ 21.1.5            │ ^21.0.6           │
│ @angular/core                     │ 21.1.5            │ ^21.0.6           │
│ @angular/forms                    │ 21.1.5            │ ^21.0.6           │
│ @angular/platform-browser         │ 21.1.5            │ ^21.0.6           │
│ @angular/platform-browser-dynamic │ 21.1.5            │ ^21.0.6           │
│ @angular/router                   │ 21.1.5            │ ^21.0.6           │
│ rxjs                              │ 7.8.2             │ ~7.8.2            │
│ typescript                        │ 5.9.3             │ ~5.9.3            │
└───────────────────────────────────┴───────────────────┴───────────────────┘

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions