I get an error when trying to call a function:
The argument type 'SomeType?' can't be assigned to the parameter type 'SomeType'
How do I fix this?
The error indicates that you're trying to pass a variable with a nullable type (SomeType?
) as an argument to a function that expects a non-nullable argument (SomeType
).
You must check that the variable is not null
first. A nullable type by definition might have the value null
. Passing that to a function that does not expect null
obviously would be bad. Check first. For example:
import 'dart:math';
final random = Random();
class Foo {}
/// Randomly returns a [Foo] instance or `null`.
Foo? maybeGetFoo() => random.nextBool() ? Foo() : null;
void printFoo(Foo fooInstance) => print(fooInstance);
void main() {
Foo? foo = maybeGetFoo();
printFoo(foo); // ERROR: The argument type 'Foo?' can't be assigned to the parameter type 'Foo'
if (foo != null) {
printFoo(foo); // OK, `foo` is now provably known to be of type `Foo`.
}
}
By checking if the local foo
variable is null
, foo
can be automatically type-promoted to a non-nullable type.
class Bar {
Foo? foo;
Bar(this.foo);
void printMember() {
if (foo != null) {
printFoo(foo); // ERROR
}
}
}
To fix this, you either must use an intermediate local variable (preferred):
void printMember() {
// Shadow with a local variable to allow automatic type promotion to occur.
final foo = this.foo;
if (foo != null) {
printFoo(foo); // OK, `foo` is now provably known to be of type `Foo`.
}
}
or you must explicitly cast to a non-nullable type:
void printMember() {
if (foo != null) {
printFoo(foo!); // Compiles.
printFoo(foo as Foo); // Compiles.
}
}
Using an explicit cast (whether with !
or with as
) usually should be a last resort. It's important that you use it only if you already know for certain that the value is not null
; if it is null
, then !
and as
will throw a TypeError
at runtime and should crash your program. Also, for the same reason why non-local variables aren't automatically type-promoted, using an explicit cast is not necessarily safe, although in practice it usually should be okay for non-pathological code.
Also note that there are some uncommon cases where even local variables might remain nullable even after being checked (e.g. the variable is reassigned after being checked). See https://dart.dev/tools/non-promotion-reasons.
I also strongly recommend reading Dart's Understanding null safety article.
Finally, this isn't really specific to null-safety; conversion from a Foo?
to Foo
is just one form of downcast, and (except for the postfix !
operator), all of the above applies to downcasts in general. Automatic type promotion from a base type (such as from Object
or dynamic
) to a derived type also would occur only for local variables or for final
, private instance variables:
class Baz {
Object maybeFoo;
Baz(this.maybeFoo);
}
void main() {
var baz = Baz(Foo());
if (baz.maybeFoo is Foo) {
printFoo(baz.maybeFoo); // ERROR
printFoo(baz.maybeFoo as Foo); // Compiles.
}
final maybeFoo = baz.maybeFoo;
if (maybeFoo is Foo) {
printFoo(maybeFoo); // OK, `maybeFoo` is now provably known to be of type `Foo`.
}
}