"The operator can’t be unconditionally invoked because the receiver can be null" error after migrating to Dart null-safety
Solution 1:
Dart engineer Erik Ernst says on GitHub:
Type promotion is only applicable to local variables. ... Promotion of an instance variable is not sound, because it could be overridden by a getter that runs a computation and returns a different object each time it is invoked. Cf. dart-lang/language#1188 for discussions about a mechanism which is similar to type promotion but based on dynamic checks, with some links to related discussions.
So local type promotion works:
String myMethod(String? myString) {
if (myString == null) {
return '';
}
return myString;
}
But instance variables don't promote. For that you need to manually tell Dart that you are sure that the instance variable isn't null in this case by using the !
operator:
class MyClass {
String? _myString;
String myMethod() {
if (_myString == null) {
return '';
}
return _myString!;
}
}
Solution 2:
The Error:
Let's say, this is your code and you're doing a null check on the instance variable and still seeing an error:
class Foo {
int? i = 0;
double func() {
if (i != null) return i.toDouble(); // <-- Error
return -1;
}
}
The method 'toDouble' can't be unconditionally invoked because the receiver can be 'null'.
The error you see in code like this is because Getters are not promoted to their non-nullable counterparts. Let's talk about the reason why.
Reason of the Error:
Let's say, there's a class Bar
which extends Foo
and override i
variable and doesn't assign it any value (keeping it null
):
class Bar extends Foo {
@override
int? i;
}
So, if you could do
print(Bar().func() * 2);
You would have run into a runtime null error, which is why getters type promotion is prohibited.
Solutions:
We need to cast away nullability from int?
. There are generally 3 ways to do this (more ways include the use of as
, is
, etc)
-
Use local variable (Recommended)
double bar() { var i = this.i; // <-- Use of local variable. if (i != null) return i.toDouble(); return -1; }
-
Use ?. with ??
double bar() { return i?.toDouble() ?? -1; // Provide some default value. }
-
Use Bang operator (!)
You should only use this solution when you're 100% sure that the variable (
i
) will never benull
.double bar() { return i!.toDouble(); // <-- Bang operator in play. }