My application has an api wrapper class originally created by typing it out in TypeScript and copying/pasting the javascript into my app.
So the class def looks like this:
var SiteApi = (function () {
function SiteApi(initially)
{
//stuff
}
SiteApi.prototype.method1 = function(){/*stuff*/};
SiteApi.prototype.method2 = function(){/*stuff*/};
return SiteApi;
})();
Now when they are on the admin page, I want to add an additional admin.js file that will contain admin methods. For example
SiteApi.prototype.Admin.method1 = function(){/*stuff*/};
I found an example that does the "end result" that I want:
// file main
function SomeObject() {
for (var i = 0, ii = SomeObject.Partial.length; i < ii; i++) {
SomeObject.Partial[i].apply(this, arguments);
}
}
SomeObject.Partial.SomeName = function() {
...
}
// file extra
SomeObject.Partial.SomeOtherName = function() {
...
}
(from: Is it possible to give javascript partial class behavior like C# or monkey patching like Ruby does?)
However, the type of class definition they are using is different.
How can I keep the TypeScript style class definition and yet do something similar to this example to add on the admin functions?
For reference, we use our class like so:
siteApi = new SiteApi();
So I imagine there will also need to be a line of code tying the admin functions into it.
Note, I'm Ok with using something like SiteApi.admin_method1
but the issue is that with TypeScript style classes the prototypes are defined in the definition and the object is executed, so it doesn't seem straightforward how to add in more prototypes later.
Extend SiteApi
but shadow the original, e.g. your admin.js loaded after would contain something like
SiteApi = (function (old_SiteApi) {
function SiteApi() {
old_SiteApi.apply(this, arguments);
// further construction
this.admin_method1 = function () {/* some admin instance method */};
}
SiteApi.prototype = Object.create(old_SiteApi.prototype);
// add more prototype things
SiteApi.prototype.admin_method2 = function () {/* admin stuff through prototype */},
return SiteApi;
}(SiteApi));
Let SiteApi
know to expect more stuff later, e.g. the original definition would become
var SiteApi = (function () {
function SiteApi(initially) {
//stuff
var i;
for (i = 0; i < SiteApi.Extras.length; ++i) {
SiteApi.Extras[i].apply(this);
}
}
SiteApi.Extras = [];
SiteApi.prototype.method1 = function () {/* stuff */};
SiteApi.prototype.method2 = function () {/* stuff */};
return SiteApi;
}());
Then the admin.js would do
SiteApi.Extras.push(
function () {
// stuff to make `this` into an Admin object
this.admin_method1 = function () {/* some admin instance method */};
}
);
The prototype of SiteApi
is still exposed, if you don't need to do more construction and just need new methods you could simply add them in admin.js
Object.assign(SiteApi.prototype, {
admin_method1: function () {/* admin stuff through prototype */},
admin_method2: function () {/* more admin stuff through prototype */}
});
This last option is the only one which will effect instances of SiteApi created before admin.js was loaded.
Of course, you could mix options 2 and 3 together as well. Similarly, you could go with option 1 but call the new constructor a different name rather than shadowing the original, like AdminApi, and use that instead of SiteApi on the admin page.