Marcel
Marcel

Reputation: 9609

Dart TypeError: type is not a subtype of type Null

Consider the following code:

void printInt(int i) => print(i);
void printString(String s) => print(s);

void printSomething(Object o) {
  final printer = {
    int: printInt,
    String: printString,
  }[o.runtimeType];
  print('Printer is $printer');
  printer(o);
}

void main() => printSomething('Hello');

It prints the correct printString function and then crashes with the following exception:

TypeError: "Hello": type 'String' is not a subtype of type 'Null'

Why does that happen?

Upvotes: 2

Views: 1157

Answers (1)

julemand101
julemand101

Reputation: 31299

The error comes from the fact that your map has been given the type Map<Type, void Function(Null)> since that is the only type it can use based on the content of you list.

The problem is that Dart cannot give your map another type since anything else would not be valid from the perspective of the type system. Let's say the type was Map<Type, void Function(Object)>. Well, we are then allowed to send any object into a method from this map. But that is not allowed since your two methods in the map clearly are defined as accepting int and String and not Object.

We can either give it the type Map<Type, void Function(int)> since we have a method taking a String.

Also, Map<Type, void Function(dynamic)> has the same problem as Object since both methods are clearly defined to taking a precise type.

So Dart will instead use Null as the type of the parameter since the only thing we know is valid to give both methods are the null value.

And since you are then trying to give a String as parameter to a method with the signature of void Function(Null) you are getting an error from the type system.

If you want you code to run, you need to tell the type system to keep quite about what you are doing. To do that, you should use dynamic for the type of method you are receiving from the map:

void printInt(int i) => print(i);
void printString(String s) => print(s);

void printSomething(Object o) {
  final dynamic printer = {
    int: printInt,
    String: printString,
  }[o.runtimeType];
  print('Printer is $printer');
  printer(o);
}

void main() => printSomething('Hello');

Upvotes: 2

Related Questions