How to check if a type is a subtype of another in dart
Asked Answered
Y

4

5

I've recently found myself in a situation where I wanted to check if a Type is a subtype of another Type this is what I've tried

 abstract class Record{}
 class TimeRecord extends Record{}
 
 void test(){
   print(TimeRecord is Record); // return false but why ??
 }
Yellowlegs answered 8/9, 2021 at 16:3 Comment(3)
There is no way to do this with Type objects. There generally isn't much you actually can do with Type objects. What are you ultimately trying to do? There possibly is a better way to accomplish your goal.Dardani
In fact, I've created a generic class which accept type extending a given class and I have a list of that generic class my problem is that I'm trying to add and element at runtime in that list and if I don't check that the element is not satisfying that constraint it will raise an exceptionYellowlegs
But I'll try it another way, thank you for your adviceYellowlegs
M
11

The only time it makes sense to check if one type is a subtype of another type is when at least one of the types is a type variable. (Otherwise, you can just look at the source and write a constant true or false into the code).

There is a way to check whether one type is a subtype of another, and it does use the is operator, but you need to have an instance as the first operand and a type as the second. You can't just create an instance of an unknown type, so we instead rely in Dart's covariant generics:

bool isSubtype<S, T>() => <S>[] is List<T>;

(You can use any generic class, or even create your own, instead of using List. All it needs is a way to create the object.)

Then you can write:

 print(isSubtype<TimeRecord, Record>()); // true!
Micky answered 9/9, 2021 at 8:42 Comment(3)
So if I understand, generics only works for static types we cannot pass a runtimeType to a generic function, can we ?Yellowlegs
Correct. A Type object is just an object, it is not a type and cannot be used where a type is used (as a type argument or in an is or as operator). Keep types as types as long as possible, and only convert them to Type objects if you need to (which should preferably be never, Type objects just aren't that great to work with).Micky
Underrated trick with the lists!Coronation
K
4

The is keyword is used to check if an object instance is an object of type T, and not if a type is another type:

abstract class Record{}
class TimeRecord extends Record{}
 
void test(){
  print(TimeRecord() is Record); // returns true!
}
Kelle answered 8/9, 2021 at 16:7 Comment(2)
Thanks for reaching me out but what i f I want a static type checking in reality I don't want to instantiate the class because if it has parameters, and you don't know them in advance it will be impossible to use this approachYellowlegs
If you want to use is on a type (class) , I guess u'll be able to do it using reflection... (dart:mirrors or reflectable package) Problem is they are not compatible with flutter as far as I knowKelle
R
4

Just to add up to @lrn answer. You could also do something like:

extension NullableObjectsExtensions<T> on T {
  bool isSubtypeOf<S>() => <T>[] is List<S>;
  bool isSupertypeOf<S>() => <S>[] is List<T>;
}

So this way you can test any variable anywhere.

Rudiment answered 31/1, 2023 at 17:34 Comment(0)
D
2

If you have multiple types that you want to test again, wish to use a switch statement with Dart patterns, but don't already have an instance of the type you want to check, you can create an instance of a generic class parameterized on that type and then use variable patterns on that instance. For example:

class SubtypeOf<T> {}

void foo<T>() {
  switch (SubtypeOf<T>()) {
    case SubtypeOf<int> _:
      print('int');
    case SubtypeOf<List<int>> _:
      print('List<int>');
    case SubtypeOf<String> _:
      print('String');
    default:
      print('Unknown');
  }
}

void main() {
  foo<int>();       // Prints: int
  foo<List<int>>(); // Prints: List<int>
  foo<String>();    // Prints: String
  foo<double>();    // Prints: Unknown
}
Dardani answered 1/5 at 17:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.