5

I'm using the Bloc pattern and have the following code to define my states:

import 'package:meta/meta.dart'

@immutable
abstract class UiState {}

class Loading extends UiState {}

class Success extends UiState {
  Success(this.message);

  final String message;
}

class Failure extends UiState {}

I try to use a UiState as follows:

class MyWidget extends StatelessWidget {
  const MyWidget({
    Key key,
    @required this.uiState,
  }) : super(key: key);

  final UiState uiState;

  Widget build(BuildContext context) {
    if (uiState is Success) {
      return Text(uiState.message);
    }
    ...
  }
}

But VSCode tells me that "The getter 'message' isn't defined for the class 'UiState'".

I've used smart casts before and they did work. But in this instance, I'm not able to figure out why it's not working.

My pubspec has the following:

environment:
  sdk: ">=2.1.0 <3.0.0"

So, I assume my dart version is atleast 2.1.0.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
AnEnigmaticBug
  • 939
  • 9
  • 17
  • To work around this issue as of the time of asking this question, I'm casting `uiState` explicitly inside the `if`s. Which is non-ideal given that the language supports smart casts. – AnEnigmaticBug Jun 26 '19 at 03:04
  • 1
    Another workaround would be storing the state inside a local variable such as `final currentState = uiState;` and using `currentState` in your if statement. – krakowski Aug 29 '20 at 14:13

2 Answers2

14

is performs implicit type promotion only for local variables.

For a local variable, the compiler can deduce that the type of the local variable will not be change between the time that its type is checked with is and before the variable is used.

For a non-local variable, the compiler cannot easily make that guarantee. Non-local variables implicitly provide getter functions, which could be overridden by a derived class and which could return different values from one access to the next.

Also see:

As an alternative to an explicit cast, you of course could store the non-local variable in a local variable first. For example:

void memberFunction() {
  final memberVariable = this.memberVariable;
  if (memberVariable is Person) {
    memberVariable.firstName = 'Bob';
  }
}

Note that this also applies to type promotion from nullable to non-nullable types, such as when doing if (someNullableVariable != null).

Also see https://dart.dev/tools/non-promotion-reasons for some other reasons why automatic type promotion might not occur.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
0

You are using BlocProvider but you have not wrapped your widget/scaffold with BlocProvider and BlocBuilder.

Do it like this:

 BlocProvider(
                create: (final context) => SubjectBloc(),
                child: BlocBuilder<SubjectBloc, SubjectState>(
                  builder: (final context, final state) {
                    if (state is Success) {
                      return const Text('data');
                    }
                    return Center(child: CircularProgressIndicator());
                  },
                ),
              ),
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Srasti Verma
  • 109
  • 1
  • 8