angular_analyzer_plugin icon indicating copy to clipboard operation
angular_analyzer_plugin copied to clipboard

Output event in two-way binding (of type dynamic) is not assignable to component input (of type String)

Open zoechi opened this issue 7 years ago • 17 comments

image

  String get title => post.title;

zoechi avatar Mar 22 '18 09:03 zoechi

In contrary to #523 this one is not related to | async

zoechi avatar Mar 22 '18 09:03 zoechi

I do find it curious how it complains about the output type, not the input type. This implies that the logic (whatever I'm doing) thinks that String is assignable to dynamic, and not vice-versa.

MichaelRFairhurst avatar Mar 22 '18 17:03 MichaelRFairhurst

I may have put in a check that the two must be equal -- it seems like a truism that if type A is assignable to B, and B is assignable to A, that they must be equal. However, as shown in this case, that's not true in Dart.

MichaelRFairhurst avatar Mar 22 '18 17:03 MichaelRFairhurst

I got the same error and lots of similar ones all over my project.

Some more examples:

warning: Attribute value expression (of type dynamic) is not assignable to component input (of type TemplateRef) when using code similar to:

<template #picker>
  <datepicker></datepicker>
</template>
<template [ngTemplateOutlet]="picker"></template>

And also warning: A value of type 'dynamic' can't be assigned to a variable of type 'RateGroup'. when using the ngModelChange event directly like:

<input ... (ngModelChange)="entity.rateGroup=$event">

So it seems that TemplateRefs and ngModelChange Events use dynamic as type. That would mean the errors are all correct, its just that either the angular code generator needs to annotate them with better types or this plugin needs to infer more information.

paulsonnenschein avatar May 17 '18 11:05 paulsonnenschein

image

So should we consider this a false positive that's going to be cleaned up eventually or do we need to always have our binding variables be dynamic in the sister Dart file? Apparently ngForm only traffics in dynamics so when it tries to set the value it can't handle any typed variable.

Here currentParentGatewayId is an int in the Dart file.

Do we need to implement patterns like this (seems ugly)?

dynamic get forBinding => myRealInt;
set forBinding(dynamic value) => myRealInt = value as int;
int myRealInt = 0;

Wondering what the best practice is going to be here.

cooler-king avatar Aug 12 '18 12:08 cooler-king

I still have not been able to repro this. This is definitely not intended behavior.

Apologies on how long this has been opened. I've been working on Dart 2 lately.

I was not able to repro this even with fuzz testing, but I think it has something to do with the switch to making the analyzer use strong mode.

MichaelRFairhurst avatar Aug 12 '18 21:08 MichaelRFairhurst

Could it have something to do with using implicit-dynamic: false in our analysis options?

cooler-king avatar Aug 12 '18 22:08 cooler-king

Ah, no, but, disabling implicit downcasts absolutely would! Have you done that as well by any chance?

If so then I think it would be working as intended for this case.

Unless ngModel carries more type information than the plugin is recognizing....I think I may be able to come up with a more precise type of I try to track type validators, but that might be undecidable in general.

I'll also talk to the angular team about their thoughts for this...

Lack of a good workaround is an issue as well.

If you do indeed have implicit downcasts disabled, that is.

On Sun, Aug 12, 2018, 3:47 PM Rob Bishop [email protected] wrote:

Could it have something to do with using implicit-dynamic: false in our analysis options?

— You are receiving this because you were assigned. Reply to this email directly, view it on GitHub https://github.com/dart-lang/angular_analyzer_plugin/issues/524#issuecomment-412377178, or mute the thread https://github.com/notifications/unsubscribe-auth/ABjWe8lOOb5zrigDsp9-YZZYnwa1tyWaks5uQLCHgaJpZM4S2sV6 .

MichaelRFairhurst avatar Aug 12 '18 23:08 MichaelRFairhurst

Yes I have implicit casts set to false as well.

cooler-king avatar Aug 12 '18 23:08 cooler-king

Yeah, so that's the root of the problem. To quote myself:

I may have put in a check that the two must be equal -- it seems like a truism that if type A is assignable to B, and B is assignable to A, that they must be equal. However, as shown in this case, that's not true in Dart.

That's not true in Dart when you have implicit downcasts enabled.

dynamic x;
int y;

x = y; // always valid
y = x; // only valid with implicit-downcasts: true

here x would be ngModel, because in the definition of it, ngModelChange returns a Stream, so, Stream<dynamic>, which means $event (which correlates here to x), is dynamic. https://github.com/dart-lang/angular/blob/67d1bd06a152956e315d443042ef9da646e57552/angular_forms/lib/src/directives/ng_model.dart#L111

@leonsenft @matanlurey will be interested.

The solution to this in which the plugin tracks angular's ValueAccessor DI, which would enable us to implement checks for for instance #233. I had thought heavily on this before at some point, but I don't remember getting much clear idea of what an implementation would look like and what its limitations would be (in general, angular DI would be NP-hard to analyze without just running it).

MichaelRFairhurst avatar Aug 13 '18 01:08 MichaelRFairhurst

I have about 120 of these warnings in my project currently. I don't want to go about adding a hacky workaround for each unless it's unavoidable/best practice.

Is there a way, or could a way be added, to suppress warnings of specific types coming from the plugin before a solution is in place?

cooler-king avatar Aug 15 '18 18:08 cooler-king

You could add this to each template (top line):

<!-- @ngIgnoreWarnings: invalid_assignment -->

but you probably don't want that.

I'll see if I can't loosen this based on the fact that I hope to track the type of NgModel. But still, I'm wary because its doing exactly what its supposed to do.

It may be better to, for instance, make a directive that extends NgModel that has a type [ngModelInt]="foo", and then you wouldn't have to wrap every two-way-bound value in a casting getter/setter.

MichaelRFairhurst avatar Aug 17 '18 20:08 MichaelRFairhurst

Could the Angular team provide ngModelWhatever for all basic types and make them available alongside ngModel?

Rather than have people recreating these over and over?

I wouldn't mind using [(ngModelString)] for example over [(ngModel)]. Provides a nice clue during template development as to what types are involved.

cooler-king avatar Aug 17 '18 20:08 cooler-king

I couldn't get <!-- @ngIgnoreWarnings: invalid_assignment --> to work. Still seeing much flakiness wrt updating too.

cooler-king avatar Aug 24 '18 19:08 cooler-king

@MichaelRFairhurst it would be great if you could let us know which approach you're going to take as soon as you know it. If, for example, the only way to solve this, is by adding ngModelInt etc... directives, then we could already start to migrate our codebase with our custom directives.

These ~100 warnings in my project are haunting me in my dreams! :)

enyo avatar Aug 30 '18 10:08 enyo

Is there any update on this? Still having these warnings and it's really annoying and hides other important warnings and hints.

enyo avatar Mar 29 '19 17:03 enyo

@MichaelRFairhurst from what I can see, the new directiveTypes doesn't help either, right?

enyo avatar Mar 29 '19 17:03 enyo