TYpescript : Static methods on Function as class - 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;

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 class decorator that modifies object instance

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)

Create Class From Hybrid Interface Type

First of all, I'm very new to TS, and during my reading in
http://www.typescriptlang.org/Handbook I stop at trying to understand how Hybrid Types Interface works.
In the example of the TS:
interface ICounter {
(start: number): string;
interval: number;
reset(): void;
}
var c: ICounter;
c(10);
c.reset();
c.interval = 5.0;
So, the problem was when I tried to write a class using this interface, the problem was the line:
(start: number): string;
First I thought that this line represents a function so tried to create:
class Test implements ICounter {
interval: number;
reset(): void { }
start(start: number): string {
return "";
}
}
But this keep showing that "Types Test and ICounter have incompatible signatures", so what I'm missing here? I thought that interfaces should work the same way for classes and variables.
ICounter represents a function that has two properties—interval and reset.
This line in the interface...
(start: number): string;
...describes a way to call the function. It's shown in the example as:
c(10)
The other lines describe the function's properties—interval and reset.
c.reset();
c.interval = 5.0;
As stated in the handbook, this is used for representing JavaScript libraries that do this. So for example, the above could represent the following JavaScript code:
function counter(start) {
alert(start);
return "some string";
}
counter.reset = function() { alert('reset called'); };
counter.interval = 1;
In addition to all this, note that the class you described could be represented by the following interface:
interface ITest {
interval: number;
reset: () => void;
start: (start: number) => string;
}
class implies that you will create instances via new operator. new creates object, not function, so it is impossible to implement class, which instances can called as function. You can do something like this:
interface ICounterObject {
interval: number;
reset(): void;
}
interface ICounter extends ICounterObject {
(start: number): string;
__proto__: ICounterObject;
}
class Test implements ICounterObject {
static createCounter(): ICounter {
var counter = <ICounter>function (start: number): string {
return "";
};
counter.__proto__ = Test.prototype;
return counter;
}
interval: number;
reset(): void { }
}
Note, __proto__ is from ES6, but de-facto is supported in ES5 browsers. If you want to use function prototype members (e.g call and apply) mix prototypes:
function mixWithFunc<T extends Function>(obj: { __proto__?}, func: T) {
var objProto = <{ constructor }>obj.__proto__;
var objClass = <{ __mixedProto__ }>objProto.constructor;
var proto = <typeof obj>objClass.__mixedProto__;
if (!proto) {
proto = {};
proto.__proto__ = objProto;
['call', 'apply', 'bind'].forEach(p => proto[p] = Function.prototype[p]);
objClass.__mixedProto__ = proto;
}
(<typeof obj>func).__proto__ = proto;
Object.getOwnPropertyNames(obj).forEach(p => func[p] = obj[p]);
return func;
}
interface ICounter extends Counter {
(start: number): string;
}
class Counter {
static create() {
var self: ICounter = mixWithFunc(
new Counter(),
<ICounter>function (start: number) {
return "started with interval: " + self.interval;
});
return self;
}
interval = 1000;
reset() { this.interval = 0; }
}
Of course you can just add members to each instance of your function instead of prototyping.

knockout viewmodel and requirejs

I have recently started to work with requirejs and when I try to create a simple viewmodel I get an strange exception. The exception comes from the knockout-2.1.0.js file and the exception is "Only subscribable things can act as dependencies".
define("PageViewModel", ["knockout-2.1.0"], function(ko) {
return function PageViewModel() {
var self = this;
self.visiblePage = ko.observable("StartPage");
self.showPage = function (pageName) {
self.visiblePage(pageName);
};
};
});
As you can see the viewmodel is extremly simple and since the error is in the knockout js file, it seems like requirejs is working as it should. I have been looking at: http://knockoutjs.com/documentation/amd-loading.html
The exception occur when coming to the line: self.visiblePage = ko.observable("StartPage");
Any ideas on what I'm doing wrong?
Thanks,
Ludwig
Update:
This is the module containing the pageviewmodel:
define("ViewModelFactory", ["StorageService", "PageViewModel", "AddUnitViewModel", "AddRoomViewModel"],
function (StorageService, PageViewModel, AddUnitViewModel, AddRoomViewModel) {
//var repositoryStorage = new StorageService();
var createAddRoomVM = function () {
var vm = new AddRoomViewModel();
vm.setRepository = StorageService.getRoomRepository();
return vm;
};
var createAddUnitVM = function () {
var vm = new AddUnitViewModel();
vm.setRepository = StorageService.getUnitRepository();
return vm;
};
var createPageVM = function () {
var vm = new PageViewModel();
return vm;
};
return {
createPageVM:createPageVM,
createAddRoomVM: createAddRoomVM,
createAddUnitVM: createAddUnitVM
};
});
And the module calling the factory
define("ApplicationViewModel", ["ViewModelFactory"],
function (viewModelFactory) {
mainVM = null;
var initVM = function () {
mainVM = {
page: viewModelFactory.createPageVM(),
addRoom: viewModelFactory.createAddRoomVM(),
addUnit: viewModelFactory.createAddUnitVM()
};
};
var getVM = function (viewName) {
switch (viewName) {
case "AddRoom":
return mainVM.addRoom;
case "AddUnit":
return mainVM.addUnit;
default:
return null;
}
};
var getPageVM = function () {
return mainVM.page;
};
return {
initVM: initVM,
getVM: getVM,
getPageVM: getPageVM,
mainVM: mainVM
};
});
And the class containing the applicationViewModel:
define("Bootstrapper", ["knockout-2.1.0", "Routing", "ApplicationViewModel"],
function (ko, routing, applicationViewModel) {
var run = function () {
applicationViewModel.initVM(); <-- after here mainVM.page is null
var mainVM = applicationViewModel.mainVM;
routing.initRouting(applicationViewModel);
ko.applyBindings(mainVM);
routing.showView("StartPage");
alert("Start");
};
return {
run: run
};
})
Your problem may have been caused by Knockout 2.1, which didn't work well when ko was not a global variable.
Knockout 2.2 should work fine, and I see from your comment this did indeed fix the problem.