From a string I'm trying to instantiate a class (my marionette view). I found a way that works but this way has a problem where I can't actually pass a parameter to the instantiated class.
It seems when I call typeMapping[viewType] it's actually returning me Show.OneNode() instead of just Show.OneNode
class Show.TwoNode extends App.ItemView
template: "templates/two"
class Show.OneNode extends App.ItemView
template: "templates/one"
class Show.Layout extends App.Layout
onShow: =>
typeMapping = {
one: Show.OneNode
two: Show.TwoNode
}
viewType = "one"
view = new typeMapping[viewType]
model: #model
again, I would have rather made this a comment, but hey that's life. Have you tried wrapping your values from your key/value pairs in quotes to force them as strings?
typeMapping = {
one: "Show.OneNode",
two: "Show.TwoNode"
}
Related
I am using the flutter Mobx for state management.
I have a simple class:-
class A {
int x;
A(this.x);
}
How can I observe if x changes inside the class in another Mobx store:-
class MyStore extends _MyStore with _$MyStore {
Subs(A a) : super(a);
}
abstract class _MyStore with Store {
#observable
A a;
_Subs(this.a)
}
I want MyStore to observe the a.x.
Is it possible, if yes how?
I ran in to the same issue the other day using flutter mobx ^1.2.1+3 (dart) and
flutter_mobx ^1.1.0+2.
The first thing that comes to my mind is to annotate the field in question, I.e x with the #observable attribute. But it doesn't seem to be effective outside a store class.
So you have to observe the field using the Observable class.
To make it work your code should look something like this:
class A {
//replace with less verbose "var"
Observable<int> x = Observable(0);
A(this.x);
}
class MyStore extends _MyStore with _$MyStore {
Subs(A a) : super(a);
}
abstract class _MyStore with Store {
A a;
_Subs(this.a)
//Will be calculated whenever a change to a.x is observed.
#computed
int get xSquare => a.x.value * a.x.value;
}
As you can see I removed the observable attribute from a, since it does not need to be observed if you want to react to changes to a.x in your store. You probably noticed that you have to access the value of the observable using .value.
That should conclude how you observe a field of a class external to the store, inside your store.
I am not sure that this would be helpful since it is Javascript/Typescript, but that's what I would do :
class Foo {
#observable name = 'foo'
}
class Bar {
foo: Foo
constructor(instanceOfFoo) {
this.foo = instanceOfFoo
autorun(() => {
// Logs foo name when it changes
console.log(this.foo.name)
})
reaction(
() => this.foo.name,
() => {
// Logs foo name when it changes
console.log(this.foo.name)
}
)
}
#observable
name = 'bar'
#computed
get fooNamePlusBarName {
// recomputes automatically whenever foo or bar name changes
return this.foo.name + this.name
}
}
Basically you pass Foo instance to the Bar constructor (or just use imported singleton if it fits you), then you have 3 options: computed, reaction and autorun
I came to know that dart mirrors is disabled in flutter but hope that there might be some alternate way to achieve. Mirrors must not be disabled in flutter, it is an important & must have feature.
import 'package:reflectable/mirrors.dart';
import 'package:reflectable/reflectable.dart';
const reflector = const Reflector();
class Reflector extends Reflectable
{
const Reflector() : super(
invokingCapability,
typingCapability,
reflectedTypeCapability,
);
}
#reflector
class Dictionary
{
String english, myLang;
int index;
}
main() {
test();
}
test()
{
ClassMirror classMirror = reflector.reflectType(Dictionary);
classMirror.declarations.values.forEach((field)
{
VariableMirror variableMirror = field;
/*??????????????????????????????????????????
Now How To Get Field types i.e. String & int
How to instantiate class object
How to set fields values
???????????????????????????????????????????*/
});
}
Runtime object instantiation:
Use the method newInstance from ClassMirror. The first argument is the constructor name. Like you haven't name constructors, simple pass an empty string. The second argument are an array of positional constructor arguments. No constructor, empty array.
Dictionary dic = classMirror.newInstance("", []);
Set fields values:
Use the method invokeSetter from InstanceMirror. The first argument is the field name and the second is the value.
InstanceMirror instanceMirror = reflector.reflect(dic);
instanceMirror.invokeSetter("index", 3);
So far I am able to know field(s) type:
ClassMirror classMirror = reflector.reflectType(Dictionary);
VariableMirror variableMirror = classMirror.declarations["english"] as VariableMirror;
Type type = variableMirror.dynamicReflectedType;
print("field: " + variableMirror.simpleName + " has type: " + type.toString());
Now remaining:
Runtime object instantiation?
How to set fields value of instantiated object?
For sure this kind of stuff could be implemented in some other way but I'm still curious why TS doesn't warn. Same structures could have different data.
class ComponentContainer<TComponent> extends Array<TComponent> {}
class Context<TComponent> extends Array<ComponentContainer<TComponent>> {}
///////////////////////////////////////////////////////
class Component<T> { constructor(public value: T) {} }
class Movable extends Component<boolean> {
constructor(value: boolean = true) { super(value) }
}
class Static extends Component<boolean> {
constructor(value: boolean = true) { super(value) }
}
///////////////////////////////////////////////////////
const ctx: Context<Movable> = new Context()
ctx[0].push(new Static()) // <-- No error
EDIT
Could be a beginning of an alternative here :https://basarat.gitbooks.io/typescript/docs/tips/nominalTyping.html
Types don't presume that value should be an instance of specified class. Movable class is used as interface here:
const ctx: Context<Movable> = new Context()
If a value should be an instance of Movable class, this check is usually performed at run time with if (value instanceof Movable). It will be tricky to implement in Array subclass, it may be better for Context to implement its own API that allows to validate values instead of extending Array.
Same structures could have different data
But they don't have different data. Static conforms to Movable interface, so it doesn't cause type error. Similarly, this will work, because the object conforms to this interface:
ctx[0].push({ value: true })
And will cause TypeScript type error if it doesn't:
ctx[0].push({ value: 1 })
It's possible to additionally enforce the value to be an instance of Movable through type checks with merged interface:
interface Movable {
constructor: typeof Movable
}
class Movable extends Component<boolean> {
constructor(value: boolean = true) { super(value) }
}
It still will be possible to cheat typing system with:
ctx[0].push({ constructor: Movable, value: 1 });
After playing a bit with your code in TypeScript Playground, it seems like TypeScript is smart enough to detect that Movable and Static are basically the same type besides their name. They are both a Component<boolean> and have no properties, so it allows you to push a new Static instance into a Movable array. Only when I added a property to Movable which didn't exist in Static then TypeScript compiler showed an error, for example:
I guess that's just how TypeScript works. It doesn't necessarily prohibit you from using different types on a generic object unless the type that's given is missing properties which exist on the expected type. That's why the following also works:
Sorry for the weird title, I don't quite know how to describe what I'm trying to do in one sentence.
I have to define a bunch of classes that are all going to extend from this one class and also implement this other class.
class SoulCoughing extends Super implements BonBon { /.../ }
class MoveAside extends Super implements BonBon { /.../ }
class LetTheManGoThru extends Super implements BonBon { /.../ }
I have written a sort of wrapper function that I use as a decorator for these classes.
const Eminem = function(klass: Constructable<????>) {
const instance = new klass();
// Do stuff
}
Constructable is a little interface I'm using because otherwise TypeScript would throw an error about not having a constructor.
interface Constructable<T> {
new(): T;
}
Now here is my problem, I don't know what type to assign to parameter klass in my wrapper function? I have tried doing this:
... function(klass: Contrusctable<Super & BonBon>)
and this:
... function(klass: Contrusctable<Super | BonBon>)
I also tried modifying my constructable interface like this:
interface Constructable<T, U> {
new(): T & U;
}
... function(klass: Contrusctable<Super, BonBon>)
but I keep getting an Argument of type 'typeof SoulCoughing' is not assignable to parameter of type 'Constructable<everythingIveTriedSoFar>' error.
So my question is, what type definition should I use with the parameter klass? I know I can just use any but I'd really like to make sure that the class being passed has extended Super and implemented BonBon.
I'm going to guess that the classes SoulCoughing etc. don't actually have no-arg constructors, and therefore cannot act as Constructable<{}> at all; the most likely culprit is that Super's constructor has a mandatory argument, which would make all subclasses fail to match new() by default. Note that this also implies that your implementation of Eminem probably wants to call new klass(...) with some arguments also.
The right way to fix it is to declare Constructable<T> to be a constructor with the right argument types. Let's say Super looks like this:
class Super {
constructor(elevator: number, mezzanine: string) {
//...
}
}
Then you could define Constructable to match:
interface Constructable<T extends Super & BonBon = Super & BonBon> {
new(chump: number, change: string): T; // same args as Super
}
and Eminem like:
const Eminem = function(klass: Constructable) {
const instance = new klass(2, "rise");
// Do stuff
}
and finally:
Eminem(SoulCoughing); // no error
I only kept Constructable generic in case you wanted TypeScript to preserve the type of the particular subclass, like so:
const SlimShady = function <T extends Super & BonBon>(klass: Constructable<T>): T {
return new klass(2, "fat");
}
// returns same type as passed-in constructor
const cutLean: MoveAside = SlimShady(MoveAside);
Okay, hope that helps; good luck!
I have created a class that extends Array. I want to execute arbitrary code before calling the inherited push function.
class newArray extends Array{
//execute any logic require before pushing value onto array
this.push(value)
}
The solution I found was to create a new function in the subclass that has the same name as the inherited function. In this case push. Then inside the overriding function the inherited function is called via the super keyword.
class newArray extends Array{
push(value) {
//execute any logic require before pushing value onto array
console.log(`pushed ${value} on to array`)
super.push(value)
}
}
var array = new newArray
array.push('new Value')