The argument type 'SomeType?' can't be assigned to the parameter type 'SomeType'

Issue

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?

Solution

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.

Note that automatic type-promotion can occur only for local variables. It will not work for non-local variables (such as global variables or member variables):

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:

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`.
  }
}

Answered By – jamesdlin

Answer Checked By – Candace Johnson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *