通过生成构造函数将超类注入原始对象
Posted
技术标签:
【中文标题】通过生成构造函数将超类注入原始对象【英文标题】:Inject super class to raw object by generating constructor 【发布时间】:2017-03-12 20:14:42 【问题描述】:我正在制作一个用 Typescript2.0 编写的库,也可以从 javascript 中使用。
我有一个类 Component
和一个由 Typescript 制作的函数 registerComponent
。
我需要通过调用registerComponent
来存储继承Component
的类的构造函数。我的库可以自动实例化注册的组件。
在某些情况下,方法的参数可能不是函数而是对象。我需要将对象转换为生成传递对象的构造函数。
但是,该构造函数也应该扩展 Component
类。
所以,我的意思是我想将一个类作为超类注入一个函数,该函数将使用 typescript 生成给定对象。
这是在 registerComponent 中处理原始对象的部分。
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;
obj
由用户提供普通对象。我认为这段代码可以工作,但实际上当我使用带有 new 关键字的构造函数时,这段代码会填充错误Uncaught TypeError: Class constructor Component cannot be invoked without 'new'
。
该异常会在代码Component.call(this)
上引发。
如何通过注入超类创建有效的构造函数?
我很抱歉在这样模棱两可的帖子中提问。但现在我想我需要发布我想要实现的完整界面。
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
// I need some code here to wrap c as constructor
public static instanciate(name:string):Component
return new Registory.registeredContructors[name]();
// When User want to register component 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");
// When user want to register component via plain object
Registory.registerComponent("C2",
someProperty:"Hello C2",
f1:function()
return this.baseFunction() + this.someProperty;
);
const c2:Component = Registory.instanciate("C2");
// This is the test c1 and c2 should pass
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);
【问题讨论】:
不清楚您要做什么,例如您有for (let key in obj)
,但这是什么obj
? registerComponent
函数的用途是什么?
我很抱歉。但是,我编辑了我的帖子。并且,'obj' 是我想转换继承Component
的构造函数的普通对象。 registerComponent
是一种将构造函数注册到库的方法,如果需要该组件,库稍后会实例化它们。
您添加的代码根本无效。几个例子:(1)Component. baseFunction
假设返回void
,但实现返回string
。 (2)registeredConstructors:[ key:string]: (new()=>Component);
是什么?你用[
开始它,但它永远不会关闭。你能解决它吗?
我解决了这个问题。再次感谢您。
【参考方案1】:
在我看来,如果我理解正确的话,你的场景可以更容易地解决:
abstract class Component
constructor(props: any)
type ComponentConstructor =
new (props: any): Component;
name: string;
;
const REGISTRY = as [name: string]: ComponentConstructor ;
function registerComponent(ctor: ComponentConstructor)
REGISTRY[ctor.name] = ctor;
function instantiateComponent(name: string, props: any): Component;
function instantiateComponent<T extends Component>(name: string, props: any): T
if (typeof REGISTRY[name] !== "function")
return null;
return new REGISTRY[name](props) as T;
class MyComponent1 extends Component
registerComponent(MyComponent1);
class MyComponent2 extends Component
registerComponent(MyComponent2);
let comp1 = instantiateComponent("MyComponent1", ); // typeof comp1 is Component
let comp2: MyComponent2 = instantiateComponent("MyComponent2", ); // typeof comp2 is MyComponent2
(code in playground)
编辑
好的,既然我明白了你想要什么,那就更容易提供帮助了。 我仍然需要清理你的代码,但这是你想要的:
interface IComponent
someProperty: string;
f1(): string;
abstract class Component implements IComponent
abstract someProperty: string;
abstract f1(): string;
public baseFunction(): string
return "This is base ";
type ComponentConstructor = new (): Component ;
abstract class ComponentFromObject extends Component
constructor(obj: IComponent)
super();
Object.assign(this, obj);
class Registory
private static registeredConstructors: [key: string]: ComponentConstructor = ;
public static registerComponent(name: string, c: ComponentConstructor | IComponent): void
if (typeof c === "function")
Registory.registeredConstructors[name] = c;
else
Registory.registeredConstructors[name] = ComponentFromObject.bind(null, c);
public static instanciate(name: string): Component
return new Registory.registeredConstructors[name]();
const registory = new Registory();
// When User want to register component 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");
// When user want to register component via plain object
Registory.registerComponent("C2",
someProperty: "Hello C2",
f1: function()
return this.baseFunction() + this.someProperty;
);
const c2: Component = Registory.instanciate("C2");
// This is the test c1 and c2 should pass
console.log(c1 instanceof Component);
console.log(c2 instanceof Component);
console.log(c1.f1() === "This is base Hello C1");
console.log(c2.f1() === "This is base Hello C2");
console.log(c1 instanceof C1);
(code in playground)
【讨论】:
很抱歉让您误会了。我想将普通对象的属性合并到通过实例化组件生成的类中。我附加了一些描述我想要实现的接口的代码。不过,谢谢你的回答。 检查我修改后的答案以上是关于通过生成构造函数将超类注入原始对象的主要内容,如果未能解决你的问题,请参考以下文章
Java 中的继承——创建子类的对象也会调用超类的构造函数。为啥?