Here I have defined a method definition with optional named parameter.
class PostBuilder extends StatefulWidget {
final Future<List<Submission>> Function({String? next}) postFetcher;
...
...
}
I can able to invoke that function as expected like below.
class _PostBuilderState extends State<PostBuilder> {
...
...
_fetch() async {
var posts = await widget.postFetcher();
// or
var posts = await widget.postFetcher(next: _items.getLast()?.name);
}
But unfortunately, I cannot figure our how to use it properly and don't know the correct syntax.
PostBuilder((next) => getPosts(next))
This is syntax error that is being thrown by the compiler
error: The argument type 'Future<List<Submission>> Function(dynamic)' can't be assigned to the parameter type 'Future<List<Submission>> Function({String? next})'. (argument_type_not_assignable)
postFetcher takes a named parameter. If you want to assign an anonymous function to it, that anonymous function also must take a named parameter. The syntax for anonymous functions is the same as for named functions (the types for anonymous functions are usually omitted because they can be inferred). You therefore want:
PostBuilder(({next}) => getPosts(next))
Related
I have a classmodel in dart with a json mapper like
class DA_Field {
final String strGROUP;
DA_Field({
required this.strGROUP, });
static DA_Field fromJson(json) => DA_Field(
strGROUP: json['GROUP'] as String, );
}
and I want to set a attribute of the attribute strGROUP via a function - so that I can call that sub-attribute 'width' for example by:
intWidth = DA_Field.strGROUP.width
My first attempt was to create a setter - but after a lot of google, I only get in touch to create a setter for the whole modelclass, not for all of the single attributes.
The values should be calculated by a function outside of the class - I thought maybe this could be possible by .forEach function - like ?
DA_Field.forEach((k,v) => k.width = functionxx(k));
But i get following errors:
error: The setter 'width' isn't defined for the type 'DA_Field'. (undefined_setter...)
error: The argument type 'void Function(DA_Field, dynamic)' can't be assigned to the parameter type 'void Function(DA_Field)'. (argument_type_not_assignable)
Can anyone give me a suggestion on how to do that?
Thanks..
What is difference between Function and Function() in Dart/Flutter?
for example in such a code
final Function x;
final Function() x;
As stated in the Function documentation, it is:
The base class for all function types.
A variable declared with type Function therefore can be assigned any function. However, you won't get any type-safety when invoking it.
Meanwhile a Function() type is a function with an unspecified (i.e., dynamic) return type and that takes zero arguments.
I'd like to store instances of models in a common provider using their classes or interfaces as a keys and then pop them up by class references. I have written some code:
class Provider {
public function new() { }
public function set<T:Any>(instance:T, ?type:Class<T>) {
if (type == null)
type = Type.getClass(instance);
if (type != null && instance != null)
map.set(type, instance);
}
public function get<T:Any>(type:Class<T>):Null<T> {
return cast map.get(type);
}
var map = new Map<Class<Any>, Any>();
}
...alas, it's even doesn't compile.
Probably I have to use qualified class name as a key rather than class/interface reference? But I'd like to keep neat get function design that takes type as argument and returns object just of type taken, without additional type casting.
Is it possible or should I change my approach to this problem?
The issue of using Class<T> as a Map key come up every so often, here is a related discussion. The naive approach of Map<Class<T>, T> fails to compile with something like this:
Abstract haxe.ds.Map has no #:to function that accepts haxe.IMap<Class<Main.T>, Main.T>`
There's several different approaches to this problem:
One can use Type reflection to obtain the fully qualified name of a class instance, and then use that as a key in a Map<String, T>:
var map = new Map<String, Any>();
var name = Type.getClassName(Main);
map[name] = value;
For convenience, you would probably want to have a wrapper that does this for you, such as this ClassMap implementation.
A simpler solution is to simply "trick" Haxe into compiling it by using an empty structure type ({}) as the key type. This causes ObjectMap to be chosen as the underlying map implementation.
var map = new Map<{}, Any>();
map[Main] = value;
However, that allows you to use things as keys that are not of type Class<T>, such as:
map[{foo: "bar"}] = value;
The type safety issues of the previous approach can be remedied by using this ClassKey abstract:
#:coreType abstract ClassKey from Class<Dynamic> to {} {}
This still uses ObjectMap as the underlying map implementation due to the to {} implicit cast. However, using a structure as a key now fails at compile time:
var map = new Map<ClassKey, Any>();
map[{foo: "bar"}] = value; // No #:arrayAccess function accepts arguments [...]
I created an extension method that lets me treat a List as DbSet for testing purposes (actually, I found this idea in another question here on stack overflow, and it's been fairly useful). Coded as follows:
public static DbSet<T> AsDbSet<T>(this List<T> sourceList) where T : class
{
var queryable = sourceList.AsQueryable();
var mockDbSet = new Mock<DbSet<T>>();
mockDbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
mockDbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
mockDbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
mockDbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
mockDbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>(sourceList.Add);
mockDbSet.Setup(d => d.Find(It.IsAny<object[]>())).Callback(sourceList.Find);
return mockDbSet.Object;
}
I had been using Add for awhile, and that works perfectly. However, when I try to add the callback for Find, I get a compiler error saying that it can't convert a method group to an action. Why is sourceList.Add an Action, but sourceList.Find is a method group?
I'll admit I'm not particularly familiar with C# delegates, so it's likely I'm missing something very obvious. Thanks in advance.
The reason Add works is because the List<T>.Add method group contains a single method which takes a single argument of type T and returns void. This method has the same signature as an Action<T> which is one of the overloads of the Callback method (the one with a single generic type parameter, Callback<T>), therefore the List<T>.Add method group can be converted to an Action<T>.
With Find, you are trying to call the Callback method (as opposed to Callback<T>) which expects an Action parameter (as opposed to Action<T>). The difference here is that an Action does not take any parameters, but an Action<T> takes a single parameter of type T. The List<T>.Find method group cannot be converted to an Action because all the Find methods (there is only one anyway) take input parameters.
The following will compile:
public static DbSet<T> AsDbSet<T>(this List<T> sourceList) where T : class
{
var mockDbSet = new Mock<DbSet<T>>();
mockDbSet.Setup(d => d.Find(It.IsAny<object[]>())).Callback<Predicate<T>>(t => sourceList.Find(t));
return mockDbSet.Object;
}
Note that I have called .Callback<Predicate<T>> because the List<T>.Find method expects and argument of type Predicate. Also note I have had to write t => sourceList.Find(t) instead of sourceList.Find because Find returns a value (which means it doesn't match the signature of Action<Predicate<T>>). By writing it as a lambda expression the return value will be thrown away.
Note that although this compiles it will not actually work because the DbSet.Find method actually takes an object[] for it's parameter, not a Predicate<T>, so you will likely have to do something like this:
public static DbSet<T> AsDbSet<T>(this List<T> sourceList) where T : class
{
var mockDbSet = new Mock<DbSet<T>>();
mockDbSet.Setup(d => d.Find(It.IsAny<object[]>())).Callback<object[]>(keyValues => sourceList.Find(keyValues.Contains));
return mockDbSet.Object;
}
This last point has more to do with how to use the Moq library that how to use method groups, delegates and lambdas - there is all sorts of syntactic sugar going on with this line which is hiding what is actually relevant to the compiler and what isn't.
I have the following classes & interfaces:
export interface IBody {
body : ListBody;
}
export class Element {
// ...
}
export class Paragraph extends Element implements IBody {
// ...
}
export class Character extends Element {
// ...
}
I have code where I will get an array of Element derived objects (there are more than just Paragraph & Character). In the case of those that implement IBody, I need to take action on the elements in the body.
What is the best way to see if it implements IBody? Is it "if (element.body !== undefined)"?
And then how do I access it? "var bodyElement = <IBody> element;" gives me an error.
C:/src/jenova/Dev/Merge/AutoTagWeb/client/layout/document/elements/factory.ts(34,27): error TS2012: Cannot convert 'Element' to 'IBody':
Type 'Element' is missing property 'body' from type 'IBody'.
Type 'IBody' is missing property 'type' from type 'Element'.
thanks - dave
An interface in TypeScript is a compile-time only construct, with no run-time representation. You might find section 7 of the TypeScript specification interesting to read as it has the complete details.
So, you can't "test" for an interface specifically. Done correctly and completely, you generally shouldn't need to test for it as the compiler should have caught the cases where an object didn't implement the necessary interface. If you were to try using a type assertion:
// // where e has been typed as any, not an Element
var body = <IBody> e;
The compiler will allow it without warning as you've asserted that the type is an IBody. If however, e were an Element in scope, the compiler as you've shown will check the signature of the Element and confirm that it has the properties/methods declared by IBody. It's important to note that it's checking the signature -- it doesn't matter that it may not implement IBody as long as the signature matches up.
Assuming that Element has a signature that matches IBody, it will work. If it does not, you'll get the compiler error you're receiving. But, again, if it's declared as any, the assertion will pass and at run-time, unless the type has the methods defined on IBody, the script will fail.
As your Element is the base class, you cannot check for IBody. You could declare an argument as any:
function someFeature(e: any) {
}
And then assert that the IBody is present:
function someFeature(e: any) {
var body :IBody = <IBody> e;
// do something
}
However, if you do need a run-time check, you'd need to look for the function on the prototype or as a property before using it. While that could be misleading in some cases, the interface in TypeScript also may not have caught the mismatch either. Here's an example of how you could check for the existence of a specific function.
It might look like this:
function someFeature(e: any) {
var body = <IBody> e;
if (typeof (body.someFunctionOnBodyInterface) === "undefined") {
// not safe to use the function
throw new Error("Yikes!");
}
body.someFunctionOnBodyInterface();
}