I wish to check any list pass into checkList function. What import I should use for <T>. VS Code no suggest a Quick Fix for this.
The name 'T' isn't a type so it can't be used as a type argument.
Try correcting the name to an existing type, or defining a type named 'T'.
If you want to type safe you should do this
void checkList<T>(List<T> list){
// ...
}
If you want to be able to check any list with any contents, you should use:
void checkListObject(List<Object> list) {
// ...
}
If you want to enforce that the list has a concrete type, but you don't know what that is ahead of time, you can pass a type parameter to the function:
void checkListT<T>(List<T> list) {
// ...
}
This has the following behaviour:
checkListObject(["hello", 123]); // allowed
checkListObject([123, 234]); // allowed
checkListT(["hello", 123]); // allowed, T is Object
checkListT<String>(["hello", "world"]); // allowed, T is String
checkListT<String>([123, 234]); // not allowed, T is String but given List<int>
checkListT<String>([123, "hello"]); // not allowed, T is String but given List<Object>
You can use Object instead of T.
void checkList(List<Object> list){
}
Related
Minimal reproducible code:
enum Foo {
a,
b;
String get name {
switch (this) {
case Foo.a: return 'A';
case Foo.b: return 'B';
}
}
}
void main() {
printEnum<Foo>(Foo.values);
}
void printEnum<T extends Enum>(List<T> list) {
for (var e in list) {
print(e.name);
}
}
The for loop prints
a
b
But I wanted it to print
A
B
So, how do I override the name property in the enum?
Note:
Using (e as Foo).name will solve the issue, but I have many enums in my project, so I can't cast them like this.
Also, please don't post answers like, use toUpperCase(), etc, because I just provided a simple example, but in real world, things are quite different.
You cannot override the name getter "on Enum" because it's an extension getter, not an instance getter.
Overriding, aka. late binding, of instance members only apply to actual (virtual) instance members.
Extension members are statically resolved, so a call of .name either hits the extension member, or it doesn't, and it depends entirely on the static type of the receiver. If you have an Enum e; ... e.name ... then it will call the extension member, and there is absolutely no way to change that, or change what it does.
If you want to have a custom and overridable name getter, I'd introduce an interface like
abstract class NamedEnum extends Enum {
String get name;
}
and then let all your enums implement NamedEnum.
Then you can do (enumValue as NamedEnum).name for any of your enums.
It won't interact with other enum types' extension name getter.
Casting e as dynamic works, as long as you ensure that the name property exists on the enum you are printing. Ex:
void printEnum<T extends Enum>(List<T> list) {
for (var e in list) {
print((e as dynamic).name);
}
}
I am new in Dart and works on an app that has a class look like this:
abstract class BaseUseCase <In,Out> {}
My question is then, what is In and Out?
In and Out are type arguments. They are used to allow the code in the class to use objects of an unknown type while remaining consistent and type-safe.
For example, say you wanted to have a method in a class that would take a list of any type, perform a string conversion operation on every element, and then return a strongly typed map of results:
class Stringifier<T> {
Map<T, String> stringify(List<T> input) =>
{for (final entry in input) entry: input.toString()};
}
void main() {
Stringifier<int>().stringify([1, 2, 3]);
// Result: <int, String>{1: '1', 2: '2', 3: '3'}
}
Note that the return type and input argument type use the generic T type. This ensures that only a list of the given type can be passed in, and that the resultant map will have the correct key type.
Type arguments can be used in other declarations as well, such as function declarations - indeed, the example above can be simplified, and declared outside a class:
Map<T, String> stringify(List<T> input) { /* ... */ }
More information on generics can be found in the Dart Language Tour, as well as in the "Generics" section of the Dart 2 language specification.
void main() {
List a = ["aa", "bbb", "ccccc"];
Iterable b = a.iterator;
while (b.moveNext()) {
/*The method 'moveNext' isn't defined for the type 'Iterable'.
Try correcting the name to the name of an existing method,
or defining a method named 'moveNext'.dartundefined_method
*/
print(b.current);
/* The getter 'current' isn't defined for the type 'Iterable<dynamic>'.
Try importing the library that defines 'current',
correcting the name to the name of an existing getter,
or defining a getter or field named 'current'.dartundefined_getter
*/
}
}
Multiple problems. E.g. a.iterator does not return a Iterable but instead Iterator. Also, you should not write List since that means List<dynamic> in Dart which means you are loosing type information.
The easiest way is to just use final or var and let Dart automatically use the most precise type (e.g. List<String>):
void main() {
final a = ["aa", "bbb", "ccccc"];
final b = a.iterator;
while (b.moveNext()) {
print(b.current);
}
}
Let's say I had some function that takes a generic type as an argument. How do I check within that function whether the generic type argument is nullable or not? I want do something like this:
void func<T>() {
print(T is nullable);
}
void main(){
func<int>(); //prints false
func<int?>(); //prints true
}
All I can think of to do is to check if T.toString() ends with a ? which is very hacky.
Try:
bool isNullable<T>() => null is T;
The accepted answer really just checks if the type can be null. It doesn't care about the type that you are operating the null operator on.
If you want to check if a type is a specific nullable type, a.k.a if you want to check if a type is specifically one of type DateTime? and not String?, you can't do this in dart via T == DateTime? as this conflicts with ternary operator syntax.
However, since dart allows passing nullable types into generic arguments, it's possible to it like so:
bool isType<T, Y>() => T == Y;
isType<T, DateTime?>() works.
I have come across this a lot. And #Irn method works, except for when T is type Type (when using generics), it will always return saying that T is not null.
I needed to test the actual type of Type not Type its self.
This is what I have that is working really well for me.
bool get isNullable {
try {
// throws an exception if T is not nullable
final value = null as T;
return true;
} catch (_) {
return false;
}
}
It creates a new List instance to verify if it's type is nullable or not by using the is operator which supports inheritance:
bool isNullable<T>() => <T?>[] is List<T>;
How can I get the subtypes of an element using the class DartType from the analyzer package?
for example if the type is List<String>, I would like to get String. Also will be useful to get if the type is generic.
Another more complex example would be Map<String, String> where I want to get a list of the subtypes, in this case: [String, String].
This one is a little tricky - because DartType actually itself has some super types - the one that will interest you here is ParameterizedType:
import 'package:analyzer/dart/element/type.dart';
Iterable<DartType> getGenericTypes(DartType type) {
return type is ParameterizedType ? type.typeArguments : const [];
}
I don't know if it's possible to know if the type is generic - after all, it's just a type. But you can check if the type accepts generic parameters, again, using ClassElement:
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
bool canHaveGenerics(DartType type) {
final element = type.element;
if (element is ClassElement) {
return element.typeParameters.isNotEmpty;
}
return false;
}
Hope that helps!