I'm currently developing a library using Typescript 2.0 that can be utilized from both Typescript and JavaScript.
Within the library, there is a class called Component
and a function named registerComponent
, both written in Typescript.
My goal is to store constructors of classes that inherit from the Component
class by calling the registerComponent
function. These registered components should then be able to be instantiated automatically by the library. In some scenarios, the method's argument may not be a function but an object. In such cases, I need to convert the object into a constructor function that generates the passed object.
Essentially, I want to inject a superclass into a function responsible for generating objects using Typescript.
This specific section handles raw objects within the registerComponent
function.
const newCtor = function() {
Component.call(this);
};
const properties = {};
for (let key in obj) {
properties[key] = { value: obj[key] };
}
newCtor.prototype = Object.create(Component.prototype, properties);
return newCtor;
The variable obj
represents a plain object provided by the user. Although the code snippet above was intended to work, it resulted in an error
Uncaught TypeError: Class constructor Component cannot be invoked without 'new'
when trying to use the constructor with the new keyword. The exception arises from the line Component.call(this)
.
How can I create a valid constructor while injecting a superclass?
I apologize for the confusion in my initial post. Now, I believe it's necessary to share the full interface I aim to achieve.
// Full interface example here
// This section showcases how component registration and instantiation works
class Component{
public baseFunction():string
{
return "This is base";
}
}
class Registory{
private static registeredConstructors:{[key:string]:(new()=>Component)};
public static registerComponent(name:string,c:(new()=>Component)|{[key:string]:any}):void
{
if(typeof c === "function")
{
Registory.registeredConstructors[name] = c;
return;
}else{
// Assume c is plain object
// Additional code needed here to wrap c as a constructor
}
}
public static instanciate(name:string):Component
{
return new Registory.registeredContructors[name]();
}
}
// Example showcasing component registration via Typescript class
class C1 extends Component{
public someProperty:string = "HELLO C1";
public f1():string{
return this.baseFunction() + this.someProperty;
}
}
Registory.registerComponent("C1",C1);
const c1:Component = Registory.instanciate("C1");
// Example showcasing registering a component using a plain object
Registory.registerComponent("C2",{
someProperty:"Hello C2",
f1:function(){
return this.baseFunction() + this.someProperty;
}
});
const c2:Component = Registory.instanciate("C2");
// Testing whether c1 and c2 meet expected criteria
test.true(()=>c1 instanceof Component);
test.true(()=>c2 instanceof Component);
test.true(()=>c1.f1() === "This is base Hello C1");
test.true(()=>c2.f1() === "This is base Hello C2");
test.true(()=>c1 instanceof C1);