@@ -371,7 +371,7 @@ runInEachFileSystem(() => {
371371 'TestCmp' : `<div id="{{mySignal}}"></div>` ,
372372 } ,
373373 source : `
374- import {signal, Signal, computed } from '@angular/core';
374+ import {signal} from '@angular/core';
375375
376376 export class TestCmp {
377377 mySignal = signal<number>(0);
@@ -399,7 +399,7 @@ runInEachFileSystem(() => {
399399 'TestCmp' : `<div id="{{mySignal()}}"></div>` ,
400400 } ,
401401 source : `
402- import {signal, Signal, computed } from '@angular/core';
402+ import {signal} from '@angular/core';
403403
404404 export class TestCmp {
405405 mySignal = signal<number>(0);
@@ -424,7 +424,7 @@ runInEachFileSystem(() => {
424424 'TestCmp' : `<div attr.id="my-{{mySignal}}-item"></div>` ,
425425 } ,
426426 source : `
427- import {signal, Signal, computed } from '@angular/core';
427+ import {signal} from '@angular/core';
428428
429429 export class TestCmp {
430430 mySignal = signal<number>(0);
@@ -453,7 +453,7 @@ runInEachFileSystem(() => {
453453 'TestCmp' : `<div attr.id="my-{{mySignal()}}-item"></div>` ,
454454 } ,
455455 source : `
456- import {signal, Signal, computed } from '@angular/core';
456+ import {signal} from '@angular/core';
457457
458458 export class TestCmp {
459459 mySignal = signal<number>(0);
@@ -479,7 +479,7 @@ runInEachFileSystem(() => {
479479 'TestCmp' : `<div id="{{myObject.myObject2.myNestedSignal}}"></div>` ,
480480 } ,
481481 source : `
482- import {signal, Signal, computed } from '@angular/core';
482+ import {signal} from '@angular/core';
483483
484484 export class TestCmp {
485485 myObject = {myObject2: {myNestedSignal: signal<number>(0)}};
@@ -553,4 +553,96 @@ runInEachFileSystem(() => {
553553 const diags = extendedTemplateChecker . getDiagnosticsForComponent ( component ) ;
554554 expect ( diags . length ) . toBe ( 0 ) ;
555555 } ) ;
556+
557+ [ 'name' , 'length' , 'prototype' , 'set' , 'update' , 'asReadonly' ] . forEach (
558+ functionInstanceProperty => {
559+ it ( `should produce a warning when a property named '${
560+ functionInstanceProperty } ' of a not invoked signal is used in interpolation`,
561+ ( ) => {
562+ const fileName = absoluteFrom ( '/main.ts' ) ;
563+ const { program, templateTypeChecker} = setup ( [
564+ {
565+ fileName,
566+ templates : {
567+ 'TestCmp' : `<div>{{myObject.mySignal.${ functionInstanceProperty } }}</div>` ,
568+ } ,
569+ source : `
570+ import {signal} from '@angular/core';
571+
572+ export class TestCmp {
573+ myObject = { mySignal: signal<{ ${ functionInstanceProperty } : string }>({ ${
574+ functionInstanceProperty } : 'foo' }) };
575+ }` ,
576+ } ,
577+ ] ) ;
578+ const sf = getSourceFileOrError ( program , fileName ) ;
579+ const component = getClass ( sf , 'TestCmp' ) ;
580+ const extendedTemplateChecker = new ExtendedTemplateCheckerImpl (
581+ templateTypeChecker , program . getTypeChecker ( ) , [ interpolatedSignalFactory ] , { }
582+ /* options */
583+ ) ;
584+ const diags = extendedTemplateChecker . getDiagnosticsForComponent ( component ) ;
585+ expect ( diags . length ) . toBe ( 1 ) ;
586+ expect ( diags [ 0 ] . category ) . toBe ( ts . DiagnosticCategory . Warning ) ;
587+ expect ( diags [ 0 ] . code ) . toBe ( ngErrorCode ( ErrorCode . INTERPOLATED_SIGNAL_NOT_INVOKED ) ) ;
588+ expect ( getSourceCodeForDiagnostic ( diags [ 0 ] ) ) . toBe ( `mySignal` ) ;
589+ } ) ;
590+
591+ it ( `should not produce a warning when a property named ${
592+ functionInstanceProperty } of an invoked signal is used in interpolation`,
593+ ( ) => {
594+ const fileName = absoluteFrom ( '/main.ts' ) ;
595+ const { program, templateTypeChecker} = setup ( [
596+ {
597+ fileName,
598+ templates : {
599+ 'TestCmp' : `<div>{{mySignal().${ functionInstanceProperty } }}</div>` ,
600+ } ,
601+ source : `
602+ import {signal} from '@angular/core';
603+
604+ export class TestCmp {
605+ mySignal = signal<{ ${ functionInstanceProperty } : string }>({ ${
606+ functionInstanceProperty } : 'foo' });
607+ }` ,
608+ } ,
609+ ] ) ;
610+ const sf = getSourceFileOrError ( program , fileName ) ;
611+ const component = getClass ( sf , 'TestCmp' ) ;
612+ const extendedTemplateChecker = new ExtendedTemplateCheckerImpl (
613+ templateTypeChecker , program . getTypeChecker ( ) , [ interpolatedSignalFactory ] , { }
614+ /* options */
615+ ) ;
616+ const diags = extendedTemplateChecker . getDiagnosticsForComponent ( component ) ;
617+ expect ( diags . length ) . toBe ( 0 ) ;
618+ } ) ;
619+
620+ it ( `should not produce a warning when a property named ${
621+ functionInstanceProperty } of an object is used in interpolation`,
622+ ( ) => {
623+ const fileName = absoluteFrom ( '/main.ts' ) ;
624+ const { program, templateTypeChecker} = setup ( [
625+ {
626+ fileName,
627+ templates : {
628+ 'TestCmp' : `<div>{{myObject.${ functionInstanceProperty } }}</div>` ,
629+ } ,
630+ source : `
631+ import {signal} from '@angular/core';
632+
633+ export class TestCmp {
634+ myObject = { ${ functionInstanceProperty } : 'foo' };
635+ }` ,
636+ } ,
637+ ] ) ;
638+ const sf = getSourceFileOrError ( program , fileName ) ;
639+ const component = getClass ( sf , 'TestCmp' ) ;
640+ const extendedTemplateChecker = new ExtendedTemplateCheckerImpl (
641+ templateTypeChecker , program . getTypeChecker ( ) , [ interpolatedSignalFactory ] , { }
642+ /* options */
643+ ) ;
644+ const diags = extendedTemplateChecker . getDiagnosticsForComponent ( component ) ;
645+ expect ( diags . length ) . toBe ( 0 ) ;
646+ } ) ;
647+ } ) ;
556648} ) ;
0 commit comments