从类型实例化通用对象

时间:2017-10-24 20:08:43

标签: angular typescript generics

我发现这段代码用参数实例化一个新对象T:

create<T>(type: { new(p: any): T }, val: any): T {
    return new type(val);
  }

我的目标是拥有一个可以继承的基类来初始化我的数组属性:

export class Base {
  create<T>(type: { new(p: any): T }, val: any): T {
    return new type(val);
  }

  init<T>(propertyArray: T[], input: any): void {
    if (propertyArray == null) {
      propertyArray = [];
      for (let i in input) {
        let tmpObj = this.create(T, i);
        propertyArray.push(tmpObj);
      }
    }
  }
}
class A extends Base {

  private _prop: B[];

  get prop() {
    return this._prop;
  }
  set prop(value: any) {
    this.init(this._prop, value);
  }

  constructor(obj: any) {
    super(obj);
    this.prop = obj && obj.item || null;
  }
}

但在此示例中let tmpObj = this.create(T, i);我收到此错误:

  

&#39; T&#39;仅指类型,但在此处用作值。

如何纠正此问题?

谢谢

1 个答案:

答案 0 :(得分:0)

我不确定你的其他代码是如何工作的,但你必须传入一个类型的构造函数才能构造该类型的实例。

让我们检查一下create()函数的签名:

declare function create<T>(type: { new(p: any): T }, val: any): T;

这是一个通用函数,适用于调用者想要的任何类型 T。 (遗憾地命名的)type参数是一个构造函数对象,您使用new调用该对象,并返回类型T的值。它是在运行时存在的对象,而不是仅在设计/编译时存在的类型

对类构造函数对象使用相同的名称以及类的实例类型是一种令人困惑但有用的做法:

class Foo {};

这将创建一个在运行时存在的名为Foo的类构造函数对象,在设计时存在的名为Foo的实例类型:

const foo: Foo = new Foo();

第一个Foo是类型,第二个Foo是类构造函数。这可以转化为:

var foo = new Foo();

请注意,名为Foo的类型已完全消失,因为它仅在设计时存在。关键是:即使您经常使用与类型相同的构造函数对象,它们也不可互换。泛型类型参数是类型,而不是构造函数对象。

好的,现在让我们看看你传递给create()的内容:

this.create(T, i)

嗯,T是什么?它是通用init()方法的类型参数。因此它只是设计时类型的名称,而不是运行时对象的名称。这永远不会奏效。相反,如上所述,您需要传入类型为{ new(p: any): T }的构造函数对象。但除非您将其添加到init()的参数列表中,否则您不会拥有其中之一:

init<T>(ctor: { new(p: any): T }, propertyArray: T[], input: any): void {
  // ...
  this.create(ctor, i);
  // ...
}

现在它将进行编译,但您必须在B setter中传递prop的构造函数。不是我知道B是什么,或者你是否有构造函数。并非我知道为什么init()方法仅在propertyArray参数为null时执行某些操作,因此prop setter只能工作一次。而不是我知道为什么你枚举input的键并将它们用作B的任何构造函数的参数。而且......好吧,我显然对你的其他代码感到困惑。可以说,在继续之前,您需要传递T而不是T的构造函数。

希望有所帮助;祝好运。