通过生成构造函数将超类注入原始对象

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),但这是什么objregisterComponent 函数的用途是什么? 我很抱歉。但是,我编辑了我的帖子。并且,'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)

【讨论】:

很抱歉让您误会了。我想将普通对象的属性合并到通过实例化组件生成的类中。我附加了一些描述我想要实现的接口的代码。不过,谢谢你的回答。 检查我修改后的答案

以上是关于通过生成构造函数将超类注入原始对象的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C中如何创建构造函数呢?

为啥在声明子类的对象时会调用超类的构造函数? (爪哇)

这是不是有太多依赖项无法通过构造函数注入到对象中?

Java 中的继承——创建子类的对象也会调用超类的构造函数。为啥?

ObjectInputStream - 读取对象 - 有没有办法阻止调用无参数超类构造函数?

通过构造函数注入的对象上的注册事件(PropertyChanged始终为null)