TypeScript class decorator that modifies object instance - class

I'm making a plugin for Aurelia and need a class decorator that
adds attributes to the new object instance, and
calls an external function with the new object as an argument.
I've looked through examples, and so far I've put together ("pseudo-ish" code)
return function addAndCall(target: any): any {
var original = target;
var newConstructor = function (...args) {
original.apply(this, args);
this.newAttribute = "object instance value";
ExternalModule.externalFunction(this);
};
newConstructor.prototype = Object.create(original.prototype);
newConstructor.prototype.constructor = original;
return <any>newConstructor;
}
but
I'm not entirely clear on the details here (or what is actually needed), and
it might not work properly since I'm getting Aurelia errors when using objects instantiated from classes with this decorator (and I suspect it's my decorator rather than the Aurelia framework that's buggy).
Any help and explanation would be greatly appreciated!

Why not just assign those properties to the prototype, and subsequently assign to the instance on first invocation
// decorator
function addAndCall(cb: Function, newField: string) {
// cb is now available in the decorator
return function(ctor: Function): void {
Object.defineProperty(ctor.prototype, newField, {
value: function(...args: any[]) {
return Object.defineProperty(this, newField, {
value: function(...args: any[]) {
console.log(newField, ...args);
}
})[newField](...args);
}
});
cb(ctor);
}
}
let callMe = (decoratedCtor) => console.log(decoratedCtor);
#addAndCall(callMe, 'propertyName')
class AddToMe {}
let addToMe = new AddToMe();
(<any>addToMe).propertyName(1, 2);

Here's a working version:
function addAndCall(target: any) {
var original = target;
function construct(constructor, args) {
var c: any = function () {
this.newAttribute = "object instance value";
ExternalModule.externalFunction(this);
return constructor.apply(this, args);;
}
c.prototype = constructor.prototype;
return new c();
}
var f: any = function (...args) {
return construct(original, args);
}
f.prototype = original.prototype;
return f;
}
(code in playground)

Related

Haxe macro to set null to calling instance?

Is there a way of setting a null to calling instance as a result of some "macro-function-call"?
Like so:
class A {
// ...
macro function DestroyItself() {
// ...
}
}
var a:A = new A();
// ...
a.DestroyItself();
trace(a); // "null"
Yep:
macro public function destroy(self:Expr) {
return macro $self = null;
}
// ...
a.destroy();
In non-static macro functions first Expr argument is a ref to caller instance.
Once approach would be to create generic tools to null any instance.
package ;
class Tools
{
/**
* Simply assigns null to the instance
* See more at: http://code.haxe.org/category/macros/generating-code-in-a-macro.html
*
* #param instance - Any
* #return haxe.macro.Expr
*/
public static macro function nullMe(instance : haxe.macro.Expr.ExprOf<Dynamic>) : haxe.macro.Expr
{
return macro {
${instance} = null;
};
}
}
This use the using Tools; to generically null any instance, but I would not recommend this. I'd use the per-class approach.
Main.hx
package ;
class Main {
static function main() {
// Construct
var instance = new SomeClass();
// Destroy
instance.destroy();
// Trace null
trace(instance);
}
}
SomeClass.hx
package ;
class SomeClass
{
public function new()
{
trace("Hello from SomeClass!");
}
private function preDestroy()
{
trace("The end is nigh!");
}
public macro function destroy(self : haxe.macro.Expr) : haxe.macro.Expr
{
return macro {
#:privateAccess ${self}.preDestroy();
${self} = null;
};
}
}
Compiled JS
// Generated by Haxe 3.4.2
(function () { "use strict";
var Main = function() { };
Main.main = function() {
var instance = new SomeClass();
instance.preDestroy();
instance = null;
console.log(instance);
};
var SomeClass = function() {
console.log("Hello from SomeClass!");
};
SomeClass.prototype = {
preDestroy: function() {
console.log("The end is nigh!");
}
};
Main.main();
})();

Resolving Promise Angular 2

I have the following problem.
In a function I have a promise as a return type. This function is in the class Hierarchy.
updateNodeValues(entity: String, data: {}): Promise<any>{
let jsonBody = JSON.stringify(data);
let url = environment.endpointCore + '/api/' + entity + '/' + data['id'];
return this.http.put(url, jsonBody, this.options)
.toPromise()
.then(response => {
return response;
})
.catch(this.handleError);
}
This function is in class node.
onSubmit(): void{
var currentForm = this.form.value;
var entityName = this.inflection.classify(this.node.type).toLowerCase();
var requiredData = {};
for(var i = 0; i < this.formItems.length; i++){
this.formItems[i].value = currentForm[Object.keys(currentForm)[i]];
}
for(var i=0; i<this.formItems.length; i++){
requiredData[this.globalService.camelize(this.formItems[i].label)] = this.formItems[i].value
}
Promise.resolve(this.hierarchyService.updateNodeValues(entityName, requiredData)).then(response => {
alert(response.ok);
if(response.ok){
this.globalService.showSuccessMessage('Values updated');
this.refreshGui(requiredData);
}
});
this.editMode = false;
}
The problem is that when i try to resolve promise and invoke this.refreshGui(requireddata) nothing is happening. I have read about how the fat arrow is preserving the 'context' of this, and I do not understand why invoking this method is not doing anything, while invoking successMessage produces expected outcome.
The method that I am invoking looks like this, and it is also in the class node.
private refreshGui(data: {}){
this._node.data = data;
this.objectProperties = new Array();
this.nodeChildren = new Array();
for (var property in data) {
var propertyValue = data[property];
if (propertyValue instanceof Array) {
this.nodeChildren.push({label: property, value: "total: ".concat(propertyValue.length.toString())});
} else {
this.objectProperties.push({label: property, value: propertyValue});
}
}
}
The solution that I found to be working was to implement custom event. The problem was that within the async callback resolution, the context of what this is would "get lost". The fat arrow enabled me to invoke class method with this, but the properties within the would be "lost". Because of this reason I have took the logic from the method, and put it in the callback part and set expected and needed results in some variable. This variable was passed to my custom event and set to class variable in the custom event handler appropriately.

TYpescript : Static methods on Function as class

I have a fn that inherit an existing fn ( take Angular1 $q for example )
//$q original behavior
var defer = $q.defer();
defer.promise.then(function(result){})
//or
$q( (resolve, reject) => {
//promise execution here
}).then(function(result){});
If I want to decorate it, I would do :
var Qdecorator = function($delegate) {
var Q = function(resolver:any): any {
//do some extra stuff here
return $delegate.apply($delegate, arguments);
}
//Assign the static methods here:
Q.defer = function() {
//do some stuff
return $delegate.defer.apply($delegate, []);
}
//same goes for race, when, resole reject and so on
return Q;
}
Problem is that typescript complains about
Property defer, race, when, resolve, etc... does not exist on type '(resolver: any) => any'
I tried to use the IQService, and IPromise with no luck, btu I'd like to raise a more global question :
How do I define late static methods on function() that return an object without using new
I am copying pasting the answer to my question from this link:
https://www.typescriptlang.org/docs/handbook/interfaces.html
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

Autofac: Resolving contructor parameters based on single dependency

I have a scenario which I want autofac to resolve:
Here are my classes, I would have a factory method to take NetworkCredentials and return TopLevel object, this should internally resolve the InnerType1 and InnerType2 with the NetwokCredentials
public class TopLevel
{
public TopLevel(InnerType1 type1, InnerType2 type2)
{
}
}
public class InnerType1
{
public InnerType1(NetworkCredential credential)
{
}
}
public class InnerType2
{
public InnerType2(NetworkCredential credential)
{
}
}
Registration code > would something like this work ?
builder.Register<Func<NetworkCredential, TopLevel>>(c =>
{
var context = c.Resolve<IComponentContext>();
return (cred) => context.Resolve<TopLevel>(new TypedParameter(typeof(NetworkCredential), cred));
});
The crude approach could be to do resolve each contructor argument one by one inside resolution of TopLevel
No, that will not work since you are now instructing Autofac to provide a parameter value of type NetworkCredential to the TopLevel constructor which clearly requires two parameters of totally different types.
You will have to resolve InnerType1 and InnerType2 instances first and provide these to the TopLevel resolve. Something like this:
builder.Register<Func<NetworkCredential, TopLevel>>(c =>
{
var context = c.Resolve<IComponentContext>();
return (cred) => {
var i1 = context.Resolve<InnerType1>(TypedParameter.From(cred));
var i2 = context.Resolve<InnerType2>(TypedParameter.From(cred));
return context.Resolve<TopLevel>(TypedParameter.From(i1), TypedParameter.From(i2));
};
});
Note: I'm not seeing the whole picture of your system here, but if you feel that this is crude, perhaps you should look at revising your class hierarchy. IMO there's a faint smell of "too complex" in your code here, you require two different classes to be configured with the same data which makes me want to de-duplicate :)
Similar to Peter's answer, but slightly different flavor:
builder.Register<Func<NetworkCredential, TopLevel>>(c =>
{
var resolveInnerType1 = c.Resolve<Func<NetworkCredential, InnerType1>>();
var resolveInnerType2 = c.Resolve<Func<NetworkCredential, InnerType2>>();
var resolveTopLevel = c.Resolve<Func<InnerType1, InnerType2, TopLevel>>();
return (cred) => {
var i1 = resolveInnerType1(cred);
var i2 = resolveInnerType2(cred);
return resolveTopLevel(i1, i2);
};
});

In Dart, can you retrieve metadata (e.g., annotations) at runtime using reflection?

If so, how is this accomplished? If not, are there any plans to support this in future Dart releases? I'm mostly referring to your own created custom annotations.
In this documentation link, https://www.dartlang.org/docs/spec/latest/dart-language-specification.html#h.d0rowtffuudf, it says: "Metadata is associated with the abstract syntax tree of the program construct p that immediately follows the metadata, assuming p is not itself metadata or a comment . Metadata can be retrieved at runtime via a reflective call, provided the annotated program construct p is accessible via reflection.
Reflective access to metadata is not yet implemented as of the M3 release."
Thank you.
Sample code for understanding.
import "dart:mirrors";
void main() {
var object = new Class1();
var classMirror = reflectClass(object.runtimeType);
// Retrieve 'HelloMetadata' for 'object'
HelloMetadata hello = getAnnotation(classMirror, HelloMetadata);
print("'HelloMetadata' for object: $hello");
// Retrieve 'Goodbye' for 'object.method'
var methodMirror = (reflect(object.method) as ClosureMirror).function;
Goodbye goodbye = getAnnotation(methodMirror, Goodbye);
print("'Goodbye' for object: $goodbye");
// Retrieve all 'Goodbye' for 'object.method'
List<Goodbye> goodbyes = getAnnotations(methodMirror, Goodbye);
print("'Goodbye's for object.method': $goodbyes");
// Retrieve all metadata for 'object.method'
List all = getAnnotations(methodMirror);
print("'Metadata for object.method': $all");
}
Object getAnnotation(DeclarationMirror declaration, Type annotation) {
for (var instance in declaration.metadata) {
if (instance.hasReflectee) {
var reflectee = instance.reflectee;
if (reflectee.runtimeType == annotation) {
return reflectee;
}
}
}
return null;
}
List getAnnotations(DeclarationMirror declaration, [Type annotation]) {
var result = [];
for (var instance in declaration.metadata) {
if (instance.hasReflectee) {
var reflectee = instance.reflectee;
if (annotation == null) {
result.add(reflectee);
} else if (reflectee.runtimeType == annotation) {
result.add(reflectee);
}
}
}
return result;
}
#HelloMetadata("Class1")
class Class1 {
#HelloMetadata("method")
#Goodbye("method")
#Goodbye("Class1")
void method() {
}
}
class HelloMetadata {
final String text;
const HelloMetadata(this.text);
String toString() => "Hello '$text'";
}
class Goodbye {
final String text;
const Goodbye(this.text);
String toString() => "Goodbye '$text'";
}
Output:
'HelloMetadata' for object: Hello 'Class1'
'Goodbye' for object: Goodbye 'method'
'Goodbye's for object.method': [Goodbye 'method', Goodbye 'Class1']
'Metadata for object.method': [Hello 'method', Goodbye 'method', Goodbye 'Class1']
P.S.
If Dart had supported the generic methods that I would recommend to use this code.
T getAnnotation<T>(DeclarationMirror declaration) {
for (var instance in declaration.metadata) {
if (instance.hasReflectee) {
var reflectee = instance.reflectee;
if (reflectee.runtimeType == T) {
return reflectee;
}
}
}
return null;
}
And retrieve metadata with generic method.
var goodbye = getAnnotation<Goodbye>(methodMirror);
Yes you can retrieve annotations with dart:mirrors :
import 'dart:mirrors';
#override
class A {}
main(){
TypeMirror typeOfA = reflectType(A);
// or reflectType(a.runtimeType) if a is an instance of A
// getting metadata of the class
List<InstanceMirror> metadatas = typeOfA.metadata;
for (InstanceMirror m in metadatas) {
ClassMirror cm = m.type;
// here you get the Class of the annotation
}
}