@@ -80,6 +80,161 @@ runInEachFileSystem(() => {
8080 env . driveMain ( ) ;
8181 } ) ;
8282
83+ it ( 'should type-check correctly when a backing signal input field is renamed' , ( ) => {
84+ // This test verifies that renaming the class field of an input is correctly reflected into
85+ // the TCB.
86+ env . write ( 'dir.ts' , `
87+ import {Directive, input} from '@angular/core';
88+
89+ @Directive({
90+ selector: '[dir]',
91+ })
92+ export class Dir {
93+ dir = input.required<string>();
94+ }
95+ ` ) ;
96+ env . write ( 'cmp.ts' , `
97+ import {Component} from '@angular/core';
98+
99+ @Component({
100+ selector: 'test-cmp',
101+ template: '<div [dir]="foo"></div>',
102+ })
103+ export class Cmp {
104+ foo = 'foo';
105+ }
106+ ` ) ;
107+ env . write ( 'mod.ts' , `
108+ import {NgModule} from '@angular/core';
109+ import {Cmp} from './cmp';
110+ import {Dir} from './dir';
111+
112+ @NgModule({
113+ declarations: [Cmp, Dir],
114+ })
115+ export class Mod {}
116+ ` ) ;
117+ env . driveMain ( ) ;
118+
119+ // Now rename the backing field of the input; the TCB should be updated such that the `dir`
120+ // input binding is still valid.
121+ env . write ( 'dir.ts' , `
122+ import {Directive, input} from '@angular/core';
123+
124+ @Directive({
125+ selector: '[dir]',
126+ })
127+ export class Dir {
128+ dirRenamed = input.required<string>({alias: 'dir'});
129+ }
130+ ` ) ;
131+ env . driveMain ( ) ;
132+ } ) ;
133+
134+ it ( 'should type-check correctly when an decorator-input is changed to a signal input' , ( ) => {
135+ env . write ( 'dir.ts' , `
136+ import {Directive, Input} from '@angular/core';
137+
138+ @Directive({
139+ selector: '[dir]',
140+ })
141+ export class Dir {
142+ @Input() dir!: string;
143+ }
144+ ` ) ;
145+ env . write ( 'cmp.ts' , `
146+ import {Component} from '@angular/core';
147+
148+ @Component({
149+ selector: 'test-cmp',
150+ template: '<div [dir]="foo"></div>',
151+ })
152+ export class Cmp {
153+ foo = 'foo';
154+ }
155+ ` ) ;
156+ env . write ( 'mod.ts' , `
157+ import {NgModule} from '@angular/core';
158+ import {Cmp} from './cmp';
159+ import {Dir} from './dir';
160+
161+ @NgModule({
162+ declarations: [Cmp, Dir],
163+ })
164+ export class Mod {}
165+ ` ) ;
166+ env . driveMain ( ) ;
167+
168+ // Now, the input is changed to a signal input. The template should still be valid.
169+ // If this `isSignal` change would not be detected, `string` would never be assignable
170+ // to `InputSignal` because the TCB would not unwrap it.
171+ env . write ( 'dir.ts' , `
172+ import {Directive, input} from '@angular/core';
173+
174+ @Directive({
175+ selector: '[dir]',
176+ })
177+ export class Dir {
178+ dir = input<string>();
179+ }
180+ ` ) ;
181+ env . driveMain ( ) ;
182+ } ) ;
183+
184+ it ( 'should type-check correctly when signal input transform is added' , ( ) => {
185+ env . write ( 'dir.ts' , `
186+ import {Directive, input} from '@angular/core';
187+
188+ @Directive({
189+ selector: '[dir]',
190+ })
191+ export class Dir {
192+ dir = input.required<string>();
193+ }
194+ ` ) ;
195+ env . write ( 'cmp.ts' , `
196+ import {Component} from '@angular/core';
197+
198+ @Component({
199+ selector: 'test-cmp',
200+ template: '<div [dir]="foo"></div>',
201+ })
202+ export class Cmp {
203+ foo = 'foo';
204+ }
205+ ` ) ;
206+ env . write ( 'mod.ts' , `
207+ import {NgModule} from '@angular/core';
208+ import {Cmp} from './cmp';
209+ import {Dir} from './dir';
210+
211+ @NgModule({
212+ declarations: [Cmp, Dir],
213+ })
214+ export class Mod {}
215+ ` ) ;
216+ env . driveMain ( ) ;
217+
218+ // Transform is added and the input no longer accepts `string`, but only a boolean.
219+ // This should result in diagnostics now, assuming the TCB is checked again.
220+ env . write ( 'dir.ts' , `
221+ import {Directive, input} from '@angular/core';
222+
223+ @Directive({
224+ selector: '[dir]',
225+ })
226+ export class Dir {
227+ dir = input.required<string, boolean>({
228+ transform: v => v.toString(),
229+ });
230+ }
231+ ` ) ;
232+ const diagnostics = env . driveDiagnostics ( ) ;
233+ expect ( diagnostics . length ) . toBe ( 1 ) ;
234+ expect ( diagnostics [ 0 ] . messageText )
235+ . toBe ( `Type 'string' is not assignable to type 'boolean'.` ) ;
236+ } ) ;
237+
83238 it ( 'should type-check correctly when a backing output field is renamed' , ( ) => {
84239 // This test verifies that renaming the class field of an output is correctly reflected into
85240 // the TCB.
0 commit comments