I used the following code to define a function type
typedef DownloadCallback = Future<StreamedResponse> Function<T>(
BuildContext context,
T fileIdentifier,
);
And created a function that is similar to the type
Future<StreamedResponse> publicFileDownloader(
BuildContext context,
String url,
) {
final request = Request('GET', Uri.parse(url));
return Client().send(request);
}
But I have the following error
The argument type 'Future Function(BuildContext, String)' can't be assigned to the parameter type 'Future Function(BuildContext, T)'.
How can I fix the error without using dynamic type?
This is another case where trying to specify a type ends up making Dart more confused. The problem is that the following:
final DownloadCallback downloader = publicFileDownloader;
Actually means:
final DownloadCallback<dynamic> downloader = publicFileDownloader;
Therefore, what you should do is the following:
final DownloadCallback<String> downloader = publicFileDownloader;
Next problem is wrong use of generic when you are declaring your typedef. What you actually want are properly the following:
typedef DownloadCallback<T> = Future<StreamedResponse> Function(
BuildContext context,
T fileIdentifier,
);
So the complete code would be:
typedef DownloadCallback<T> = Future<StreamedResponse> Function(
BuildContext context,
T fileIdentifier,
);
Future<StreamedResponse> publicFileDownloader(
BuildContext context,
String url,
) {
final request = Request('GET', Uri.parse(url));
return Client().send(request);
}
final DownloadCallback<String> downloader = publicFileDownloader;
Related
I am getting the following error message when using argument matcher, any, when mocking a method in dart tests using mockito in a null safe dart code base.
What steps need to be taken to fix this issue
error:
The argument type 'Null' can't be assigned to the parameter type 'int'.
Test code can be found here:
class MockNumberTriviaRepository extends Mock implements NumberTriviaRespository {}
void main() {
late GetConcreteNumberTrivia usecase;
late MockNumberTriviaRepository mockNumberTriviaRepository;
setUp(() {
mockNumberTriviaRepository = MockNumberTriviaRepository();
usecase = GetConcreteNumberTrivia(mockNumberTriviaRepository);
});
const tNumber = 1;
const tNumberTrivia = NumberTrivia(number: tNumber, text: "test");
test('should get trivia for the number from repository', () async {
//arrange
when(mockNumberTriviaRepository.getConcreteNumberTrivia(any)).thenAnswer((_) async => const Right(tNumberTrivia));
//act
final result = await usecase.execute(tNumber);
//assert
// UseCase should simply return whatever was returned from the Repository
expect(result, const Right(tNumberTrivia));
// Verify that the method has been called on the Repository
verify(mockNumberTriviaRepository.getConcreteNumberTrivia(tNumber));
verifyNoMoreInteractions(mockNumberTriviaRepository);
});
}
Implementation code can be found here:
abstract class NumberTriviaRespository {
Future<Either<Failure, NumberTrivia>> getConcreteNumberTrivia(int number);
Future<Either<Failure, NumberTrivia>> getRandomNumberTrivia();
}
abstract class Failure extends Equatable {
const Failure([List properties = const <dynamic>[]]);
}
class GetConcreteNumberTrivia {
final NumberTriviaRespository respository;
const GetConcreteNumberTrivia(this.respository);
Future<Either<Failure, NumberTrivia>> execute(int number) async {
return await respository.getConcreteNumberTrivia(number);
}
}
class NumberTrivia extends Equatable {
final String text;
final int number;
const NumberTrivia({required this.text, required this.number});
#override
List<Object?> get props => [text, number];
}
Mockito has issues with Dart Null-safety. Please see https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md.
You can override the implementation of your mock class to support a null argument by following the recipes on the link above:
class MockNumberTriviaRepository extends Mock
implements NumberTriviaRespository {
#override
Future<Either<Failure, NumberTrivia>> getConcreteNumberTrivia(int? number) =>
super.noSuchMethod(Invocation.method(#getConcreteNumberTrivia, [number]),
returnValue: Future.value(
Right<Failure, NumberTrivia>(NumberTrivia(text: "", number: 1))));
}
I am trying to convert this dart file here to use generics and I get the following error when trying to initialize an empty list in constructor.
Constant list literals can't include a type parameter as a type
argument, such as 'T'. Try replacing the type parameter with a
different
How can I create an empty list in this case. Below code can elaboreate my problem even more
old file
enum PostStatus { initial, success, failure }
class PostState extends Equatable {
const PostState({
this.status = PostStatus.initial,
this.posts = const <Post>[],
this.hasReachedMax = false,
});
final PostStatus status;
final List<Post> posts;
final bool hasReachedMax;
PostState copyWith({
PostStatus status,
List<Post> posts,
bool hasReachedMax,
}) {
return PostState(
status: status ?? this.status,
posts: posts ?? this.posts,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
);
}
#override
List<Object> get props => [status, posts, hasReachedMax];
}
new file
class PagedState<T> extends Equatable {
const PagedState({
this.status = PagedStatus.initial,
this.items = const <T>[], //ERROR HERE
this.hasReachedMax = false,
});
final PagedStatus status;
final List<T> items;
final bool hasReachedMax;
PagedState copyWith({
PagedStatus status,
List<T> items,
bool hasReachedMax,
}) {
return PagedState(
status: status ?? this.status,
items: items ?? this.items,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
);
}
#override
List<Object> get props => [status, items, hasReachedMax];
}
As the error says, constant list literals can't use a type parameter, so you must use a non-const literal: <T>[].
However, since it's a default argument and default arguments must be constants, that won't work either. You either will need to:
Use a constant sentinel value as the default and replace it with the desired default later:
const PagedState({
List<T> items = null,
this.hasReachedMax = false,
}) : items = items ?? <T>[];
Use const [] without the explicit type parameter and let automatic type conversions do the work for you.
I am pretty new in Dart and I would like to know, how to make Function defined as a property more type safe:
class NewTransaction extends StatelessWidget {
final titleController = TextEditingController();
final amountController = TextEditingController();
final Function addNewTx;
NewTransaction(this.addNewTx);
With type safety I mean, that I can determine what are the inputs and outputs. Now I can pass anything to Function object.
When declaring a Function parameter, declare the return type and parameters.
In your example, I will imagine a void return type, and a String parameter. As a result:
class NewTransaction extends StatelessWidget {
final titleController = TextEditingController();
final amountController = TextEditingController();
final void Function(String) addNewTx;
NewTransaction(this.addNewTx);
}
I am new to flutter and getting type error. I am trying to use json automated serializations.
AFTER DOING SOME TWEAKS HERE IS HOW IT LOOKS LIKE
Here is how I am trying to get the data from api
Future getMyProduct() async {
final res = await http.get('url');
final data = json.decode(res.body);
BaseResponse req = new BaseResponse.fromJson(data);
return req;
}
My BaseResponse class looks like this
import 'package:dynamicapp/model/model.dart';
import 'package:json_annotation/json_annotation.dart';
part 'response.g.dart';
#JsonSerializable()
class BaseResponse extends Object {
final int id;
final int sellingPrice;
final int totalStock;
final String productName;
final String productDesc;
final List<Image> images;
BaseResponse(this.id, this.sellingPrice, this.totalStock, this.productName,
this.productDesc, this.images);
factory BaseResponse.fromJson(Map<String, dynamic> json) => _$BaseResponseFromJson(json);
Map<String, dynamic> toJson() => _$BaseResponseToJson(this);
}
#JsonSerializable()
class Image extends Object {
final int id;
final String image;
// final int product_id;
Image(this.id, this.image);
factory Image.fromJson(Map<String, dynamic> json) => _$ImageFromJson(json);
Map<String, dynamic> toJson() => _$ImageToJson(this);
}
Could anyone please help me with this. I am stuck here. Have been trying different methods but none working. Thank you.
It looks like data is a List<dynamic>, then data.map(someFunc).toList() will take each element of data pass it to someFunc and form it back into a list of the return type of someFunc (which you will presumably want to be BaseResponse). Which tells you that someFunc needs to be a function that takes dynamic and returns BaseResponse.
You'd want to write something like this:
final data = json.decode(res.body);
List<BaseResponse> responses =
data.map((j) => BaseResponse.fromJson(j)).toList();
I'm trying to push a route to display a ListView item when that item is tapped (onTap). The onTap property for InkWell is defined as a VoidCallback. However, I would like to be able to receive a return value from the callback, indicating whether the user has modified said item in the dialog that was opened.
Assigning a Future<Null> async function to onTap seems to be OK, as per the Shrine Demo (shrine_home.dart in the flutter_gallery example):
Future<Null> _showOrderPage(Product product) async {
final Order order = _shoppingCart[product] ?? new Order(product: product);
final Order completedOrder = await Navigator.push(context, new ShrineOrderRoute(
order: order,
builder: (BuildContext context) {
return new OrderPage(
order: order,
products: _products,
shoppingCart: _shoppingCart,
);
}
));
assert(completedOrder.product != null);
if (completedOrder.quantity == 0)
_shoppingCart.remove(completedOrder.product);
}
Why and how is this working? Thanks.
Dart allows you to use a function with a non-void return value as a function with a void return value. The function will still return values as normal, but the analyzer will infer that they're of the void type and will complain if you try to use them, unless you cast them back to something else.
typedef void VoidCallback();
typedef int IntCallback();
final IntCallback i = () => 42;
void main() {
final VoidCallback v = i;
print("${v()}"); // prints 42
print(v() as int); // also prints 42
print(v().toString()); // also prints 42, but analyzer complains:
// method 'toString' isn't defined for class 'void'
}
That is why you can use a function that returns a Future<Null> as a VoidCallback.
Oops. Just realized the assignment was actually via a lambda, which is a VoidCallback:
onPressed: () { _showOrderPage(product); }
Still - it seems to be working for me in another place, where I assign a Future<Null> async function to the onPressed method of FloatingActionButton...