0

I have performed a null check but still I'm getting the below error.

error: The argument type 'String?' can't be assigned to the parameter type 'String'. (argument_type_not_assignable at [sitewalk] lib/modules/floor_plan/widgets/dialog_nested/dialog_nested.dart:122)

Screenshot below for better understanding: enter image description here

Now if I use the null assertion operator(!) the error will be gone. But I wanted to know why it's giving an error on the first place?

Is it because if we use multi thread this value can be changed which might cause an error?

Sp4Rx
  • 1,498
  • 3
  • 20
  • 37
  • make errorMessage a non-nullable `String`. Then you can use it without fallbacks / assertions for `null`. – scrimau May 15 '23 at 07:40
  • For my use case I need that `errorMessage` to be nullable. It's not about this specific widget I have faced this issue everywhere when I have a nullable param. @scrimau – Sp4Rx May 15 '23 at 07:42
  • then you have to handle `null` values, either by assertion or by fallback (`errorMessage ?? "default"`). Cause of the error is, that the `Text` widget requires a `String` parameter, and the type of `errorMessage` missmatches in the case of `null`. – scrimau May 15 '23 at 07:44
  • i think null guards from outside conditionals is not supported right now, maybe in dart3? – scrimau May 15 '23 at 07:46
  • Yes @scrimau. But I wanted to know why? I'm sure there will be an edge case for that reason this condition was implemented in the null guard. I believe on previous versions of flutter this used to work. – Sp4Rx May 15 '23 at 07:53
  • @Sp4Rx This never worked on any version of Dart, it's been this way since null-safety started. And it's a great advantage compared to other languages, that have a comparatively "loose" relationship with their nullability, where non-null means "probably not null in most cases", while Dart *guarantees* it won't be null, in *all* cases. – nvoigt May 15 '23 at 08:11
  • @nvoigt inline conditions are respected as far as i know. so he could write it as `return errorMessage != null ? Text(errorMessage) : SizedBox.shrink()`, just standard if-else-blocks are not. Theoretically, since this block is sync and dart is single threaded (in the same isolate), i dont see a problem to guarantee the non-nullability in the else clause. But i guess it is hard to analyze or there might be something im missing. – scrimau May 15 '23 at 08:30
  • in any case, this looks like a question addressed to the dart creators / maintainers, idk if stackoverflow is the right place for it. maybe propose this question as a github issue / feature request for the dart project? – scrimau May 15 '23 at 08:32
  • @scrimau No, it works the same in inline conditions, just test it in Dartpad. – nvoigt May 15 '23 at 10:12
  • 1
    @nvoigt you are correct. I think, Ivo's answer explains something i was missing. – scrimau May 15 '23 at 13:44

4 Answers4

2

The reason is actually that subclasses of your Test class may override the field with a getter that doesn't consistently give the same value back. Like this:

class Test2 extends Test {
  const Test2({super.key, super.errormessage});

  @override
  String? get errorMessage => Random().nextBool() ? null : 'aaa';
}

In this case the null check might pass the first time but when getting it for the Text it might return null

Ivo
  • 18,659
  • 2
  • 23
  • 35
  • Thanks @Ivo for explaining it in a simple manner. This is the answer I was looking for. Marking it as correct. – Sp4Rx May 15 '23 at 15:01
0

You need a variable, that is considered to be a candidate for type promotion from String? to String. The easiest way is to have a local variable:

@override
Widget build(BuildContext context) {
  final localErrorMessage = errorMessage;
  if(localErrorMessage == null) {
    return SizedBox.shrink();
  } else {
    return Text(localErrorMessage);
  }
}
nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • Yes I'm aware of these solutions. My question was more onto the reason for this error. – Sp4Rx May 15 '23 at 15:05
  • @Sp4Rx The reason, as explained in the link, is that some variables can be "promoted" from their nullable type to their non-nullable type, for example by checking them for null in an if-statement like you did. However, the variable you have does *not* get promoted, because the compiler won't do that. One reason for why it cannot be promoted is that it cannot be guaranteed to return the same thing when called again, as per the example in the other answer. If you take a local variable and assign that and use that, *that local variable* **can** be promoted to it's non-null type. – nvoigt May 15 '23 at 16:38
0

use this code

  class MyClass extends StatelessWidget {
  final String? errorMessage;
  const MyClass({Key? key, this.errorMessage,}) : super(key: key);
    @override
     Widget build(BuildContext context) {
      if (errorMessage == null) {
      return const SizedBox.shrink();
    } else {
      return Text("$errorMessage");
    }
  }
}

have good time;

-2

You can do it like:

Put bang operator to end of the 'errorMessage'

class Test extends StatelessWidget {
  final String? errorMessage;

  const Test({
    Key? key,
    this.errorMessage,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (errorMessage == null) {
      return const SizedBox.shrink();
    } else {
      return Text(errorMessage!);
    }
  }
}