AngularDart has a class called AppView, i.e. abstract class AppView<T> {}.
One (at least) of these are generated for every class annotated with @Component:
// file.dart
@Component(...)
class DashboardComponent {}
// file.template.dart (Generated)
class ViewDashboardComponent extends AppView<DashboardComponent> {}
I have code elsewhere in the framework that doesn't care what this T type is. I'm a little confused with Dart 2 what the "right" "anything" type to use. For example, I could use:
AppViewAppView<dynamic>AppView<Object>AppView<Null>AppView<void>I think more than one of these will "work". But which is the "right" one to use in this case?
You should be fine to use AppView (or AppView<dynamic>) just about anywhere. I can think of two examples where this will get you into trouble though:
If you are instantiating an AppView, you definitely want that type parameter. See the following error when you don't:
$ cat a.dart
void main() {
List<dynamic> a = ["one", "two", "three"];
List<String> b = a;
}
$ dart --preview-dart-2 a.dart
Unhandled exception:
type 'List' is not a subtype of type 'List<String>' where
List is from dart:core
List is from dart:core
String is from dart:core
#0 main (file:///Users/sam/a.dart:3:20)
#1 _startIsolate.<anonymous closure> (dart:isolate/isolate_patch.dart:279:19)
#2 _RawReceivePortImpl._handleMessage (dart:isolate/isolate_patch.dart:165:12)
If you are ever assigning a closure to a site that expects a closure with one or more typed parameters that involve T, you will see a "uses dynamic as bottom" static error (from the analyzer), and probably a runtime error as well:
$ cat f.dart
void main() {
List a = <String>["one", "two", "three"];
a.map((String s) => s.toUpperCase());
List b = ["one", "two", "three"];
b.map((String s) => s.toUpperCase());
}
$ dart --preview-dart-2 f.dart
f.dart:3:9: Error: A value of type '(dart.core::String) → dart.core::String' can't be assigned to a variable of type '(dynamic) → dynamic'.
Try changing the type of the left hand side, or casting the right hand side to '(dynamic) → dynamic'.
a.map((String s) => s.toUpperCase());
^
f.dart:6:9: Error: A value of type '(dart.core::String) → dart.core::String' can't be assigned to a variable of type '(dynamic) → dynamic'.
Try changing the type of the left hand side, or casting the right hand side to '(dynamic) → dynamic'.
b.map((String s) => s.toUpperCase());
^
(I'm not certain any Dart tool yet has complete Dart 2 runtime and compile time semantics, so this might change slightly.)
In these cases, it is best to use generic classes, generic methods, and generic typedefs to encapsulate, for a given scope, what the values of an object's type parameters might be.
I suspect there is a difference between dynamic and Object in Dart 2, and I think Günter covered this in his response, though if your code "doesn't care what this T type is", then you're probably not calling any methods on the component.
AppView<void> might be a good choice in this case, as an actual check that you actually never touch the underlying component (Object would probably serve the same purpose). See how we are allowed to access properties of a List<void> but not properties of the elements:
$ cat g.dart
void main() {
var c = <String>["one", "two", "three"];
fn(c);
fn2(c);
}
int fn(List<void> list) => list.length;
int fn2(List<void> list) => list.first.length;
$ dart --preview-dart-2 g.dart
g.dart:9:40: Error: The getter 'length' isn't defined for the class 'void'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'length'.
int fn2(List<void> list) => list.first.length;
^
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With