Typescript 从泛型类中的类型参数创建新对象

Typescript 从泛型类中的类型参数创建新对象,typescript,generics,Typescript,Generics,我正在尝试在泛型类中创建类型参数的新对象。 在我的类视图中,我有两个作为类型参数传递的泛型类型的对象列表,但是当我尝试创建新的TGridView()时,TypeScript说: 找不到符号“TGridView” 代码如下: module AppFW { // Represents a view export class View<TFormView extends FormView, TGridView extends GridView> { // T

我正在尝试在泛型类中创建类型参数的新对象。 在我的类
视图
中,我有两个作为类型参数传递的泛型类型的对象列表,但是当我尝试创建
新的TGridView()
时,TypeScript说:

找不到符号“TGridView”

代码如下:

module AppFW {
    // Represents a view
    export class View<TFormView extends FormView, TGridView extends GridView> {
        // The list of forms 
        public Forms: { [idForm: string]: TFormView; } = {};

        // The list of grids
        public Grids: { [idForm: string]: TGridView; } = {};

        public AddForm(formElement: HTMLFormElement, dataModel: any, submitFunction?: (e: SubmitFormViewEvent) => boolean): FormView {
            var newForm: TFormView = new TFormView(formElement, dataModel, submitFunction);
            this.Forms[formElement.id] = newForm;
            return newForm;
        }

        public AddGrid(element: HTMLDivElement, gridOptions: any): GridView {
            var newGrid: TGridView = new TGridView(element, gridOptions);
            this.Grids[element.id] = newGrid;
            return newGrid;
        }
    }
}
模块AppFW{
//表示一个视图
导出类视图{
//表格清单
公共窗体:{[idForm:string]:TFormView;}={};
//网格列表
公共网格:{[idForm:string]:TGridView;}={};
公共AddForm(formElement:HTMLFormElement,dataModel:any,submitFunction?:(e:SubmitFormViewEvent)=>boolean):FormView{
var newForm:TFormView=newtformview(formElement、dataModel、submitFunction);
this.Forms[formElement.id]=newForm;
返回新表单;
}
public AddGrid(元素:htmldevelment,gridOptions:any):GridView{
var newGrid:TGridView=newtgridview(元素,gridOptions);
this.Grids[element.id]=newGrid;
返回新网格;
}
}
}

我可以从泛型类型创建对象吗?

由于已编译的JavaScript已删除所有类型信息,因此不能使用
t
新建对象

您可以通过将类型传递到构造函数中,以非泛型的方式实现这一点

class TestOne {
    hi() {
        alert('Hi');
    }
}

class TestTwo {
    constructor(private testType) {

    }
    getNew() {
        return new this.testType();
    }
}

var test = new TestTwo(TestOne);

var example = test.getNew();
example.hi();
您可以使用泛型扩展此示例,以收紧类型:

class TestBase {
    hi() {
        alert('Hi from base');
    }
}

class TestSub extends TestBase {
    hi() {
        alert('Hi from sub');
    }
}

class TestTwo<T extends TestBase> {
    constructor(private testType: new () => T) {
    }

    getNew() : T {
        return new this.testType();
    }
}

//var test = new TestTwo<TestBase>(TestBase);
var test = new TestTwo<TestSub>(TestSub);

var example = test.getNew();
example.hi();
类TestBase{ 你好(){ 警报(‘基地高’); } } 类TestSub扩展了TestBase{ 你好(){ 警报(“来自sub的Hi”); } } 类test2{ 构造函数(私有测试类型:new()=>T){ } getNew():T{ 返回新的this.testType(); } } //var测试=新的测试二(TestBase); var测试=新测试二(TestSub); var-example=test.getNew(); 例如:hi();
要在泛型代码中创建新对象,需要通过其构造函数引用该类型。因此,与其写这封信:

function activatorNotWorking<T extends IActivatable>(type: T): T {
    return new T(); // compile error could not find symbol T
}
功能激活器不工作(类型:T):T{
return new T();//编译错误找不到符号T
}
你需要这样写:

function activator<T extends IActivatable>(type: { new(): T ;} ): T {
    return new type();
}

var classA: ClassA = activator(ClassA);
函数激活器(类型:{new():T;}):T{
返回新类型();
}
var classA:classA=激活剂(classA);
见这个问题:

所有类型信息在JavaScript端被擦除,因此您不能像@Sohnee states那样更新,但我更希望将类型参数传递给构造函数:

class A {
}

class B<T> {
    Prop: T;
    constructor(TCreator: { new (): T; }) {
        this.Prop = new TCreator();
    }
}

var test = new B<A>(A);
export class VW_MyData {
    
    public RawColumn: string;
    public TransformedColumn: string;


    public constructor(init?: Partial<VW_MyData>) {
        Object.assign(this, init);
        this.TransformedColumn = this.transform(this.RawColumn);
    }

    protected transform(input: string): string {
        return `Transformation of ${input}!`;
    }
}
class Sample {
    public innerField: string;

    constructor(data: Partial<Sample>) {
        this.innerField = data.innerField;
    }
}

export class GenericWithParams<TType> {
    public innerItem: TType;

    constructor(data: Partial<GenericWithParams<TType>>, private typePrototype: new (i: Partial<TType>) => TType) {
        this.innerItem = this.factoryMethodOnModel(data.innerItem);
    }

    private factoryMethodOnModel = (item: Partial<TType>): TType => {
        return new this.typePrototype(item);
    };
}

const instance = new GenericWithParams<Sample>({ innerItem : { innerField: 'test' }}, Sample);
A类{
}
B类{
道具:T;
构造函数(TCreator:{new():T;}){
this.Prop=new TCreator();
}
}
var测试=新的B(A);
导出抽象类formBase扩展基类{
受保护项={}为T;
}

它的对象将能够接收任何参数,但是,类型T只是一个typescript引用,不能通过构造函数创建。也就是说,它不会创建任何类对象 它通常是有效的 编辑1:

导出类EntityCollection{
可变:可编辑实体[]=[];
不可变:T[]=[];
编辑(索引:编号){
this.mutable[index].entity=Object.assign({},this.immutable[index]);
}
}

我试图从基类中实例化泛型。上面的例子都不适合我,因为它们需要一个具体的类型来调用工厂方法

在对此进行了一段时间的研究之后,我无法在网上找到解决方案,我发现这似乎是可行的

 protected activeRow: T = {} as T;
作品:

 activeRow: T = {} <-- activeRow now equals a new object...

没有完全回答这个问题,但是,对于这类问题有一个很好的库:(尽管它对泛型类型不起作用,因为它们在运行时并不存在(这里所有的工作都是用类名(类构造函数))完成的)

例如:

import {Type, plainToClass, deserialize} from "class-transformer";

export class Foo
{
    @Type(Bar)
    public nestedClass: Bar;

    public someVar: string;

    public someMethod(): string
    {
        return this.nestedClass.someVar + this.someVar;
    }
}

export class Bar
{
    public someVar: string;
}

const json = '{"someVar": "a", "nestedClass": {"someVar": "B"}}';
const optionA = plainToClass(Foo, JSON.parse(json));
const optionB = deserialize(Foo, json);

optionA.someMethod(); // works
optionB.someMethod(); // works

我知道晚了,但是@TadasPa的答案可以通过使用

TCreator: new() => T
而不是

TCreator: { new (): T; }
所以结果应该是这样的

class A {
}

class B<T> {
    Prop: T;
    constructor(TCreator: new() => T) {
        this.Prop = new TCreator();
    }
}

var test = new B<A>(A);
A类{
}
B类{
道具:T;
构造函数(TCreator:new()=>T){
this.Prop=new TCreator();
}
}
var测试=新的B(A);

我这样做是为了保留类型信息:

class Helper {
   public static createRaw<T>(TCreator: { new (): T; }, data: any): T
   {
     return Object.assign(new TCreator(), data);
   }
   public static create<T>(TCreator: { new (): T; }, data: T): T
   {
      return this.createRaw(TCreator, data);
   }
}

...

it('create helper', () => {
    class A {
        public data: string;
    }
    class B {
        public data: string;
        public getData(): string {
            return this.data;
        }
    }
    var str = "foobar";

    var a1 = Helper.create<A>(A, {data: str});
    expect(a1 instanceof A).toBeTruthy();
    expect(a1.data).toBe(str);

    var a2 = Helper.create(A, {data: str});
    expect(a2 instanceof A).toBeTruthy();
    expect(a2.data).toBe(str);

    var b1 = Helper.createRaw(B, {data: str});
    expect(b1 instanceof B).toBeTruthy();
    expect(b1.data).toBe(str);
    expect(b1.getData()).toBe(str);

});
类助手{
公共静态createRaw(TCreator:{new():T;},数据:any):T
{
返回Object.assign(新的TCreator(),数据);
}
公共静态创建(TCreator:{new():T;},数据:T):T
{
返回此.createRaw(TCreator,data);
}
}
...
它('create helper',()=>{
甲级{
公共数据:字符串;
}
B类{
公共数据:字符串;
public getData():字符串{
返回此.data;
}
}
var str=“foobar”;
var a1=Helper.create(A,{data:str});
expect(A.toBeTruthy()的a1实例);
expect(a1.数据),toBe(str);
var a2=Helper.create(A,{data:str});
expect(A.toBeTruthy()的a2实例);
expect(a2.数据),toBe(str);
var b1=Helper.createRaw(B,{data:str});
expect(B.toBeTruthy()的b1实例);
expect(b1.数据),toBe(str);
expect(b1.getData()).toBe(str);
});

我参加聚会要迟到了,但这就是我工作的方式。对于阵列,我们需要做一些技巧:

   public clone<T>(sourceObj: T): T {
      var cloneObj: T = {} as T;
      for (var key in sourceObj) {
         if (sourceObj[key] instanceof Array) {
            if (sourceObj[key]) {
               // create an empty value first
               let str: string = '{"' + key + '" : ""}';
               Object.assign(cloneObj, JSON.parse(str))
               // update with the real value
               cloneObj[key] = sourceObj[key];
            } else {
               Object.assign(cloneObj, [])
            }
         } else if (typeof sourceObj[key] === "object") {
            cloneObj[key] = this.clone(sourceObj[key]);
         } else {
            if (cloneObj.hasOwnProperty(key)) {
               cloneObj[key] = sourceObj[key];
            } else { // insert the property
               // need create a JSON to use the 'key' as its value
               let str: string = '{"' + key + '" : "' + sourceObj[key] + '"}';
               // insert the new field
               Object.assign(cloneObj, JSON.parse(str))
            }
         }
      }
      return cloneObj;
   }
公共克隆(sourceObj:T):T{
var cloneObj:T={}as T;
for(sourceObj中的var键){
if(sourceObj[key]数组实例){
if(sourceObj[key]){
//首先创建一个空值
让str:string='{'+key+':''}';
assign(cloneObj,JSON.parse(str))
//用实际值更新
cloneObj[key]=sourceObj[key];
}否则{
Object.assign(cloneObj,[]
}
}else if(sourceObj[key]=“object”的类型){
cloneObj[key]=this.clone(sourceObj[key]);
}否则{
if(cloneObj.hasOwnProperty(键)){
cloneObj[key]=sourceObj[key];
}否则
TCreator: { new (): T; }
class A {
}

class B<T> {
    Prop: T;
    constructor(TCreator: new() => T) {
        this.Prop = new TCreator();
    }
}

var test = new B<A>(A);
class Helper {
   public static createRaw<T>(TCreator: { new (): T; }, data: any): T
   {
     return Object.assign(new TCreator(), data);
   }
   public static create<T>(TCreator: { new (): T; }, data: T): T
   {
      return this.createRaw(TCreator, data);
   }
}

...

it('create helper', () => {
    class A {
        public data: string;
    }
    class B {
        public data: string;
        public getData(): string {
            return this.data;
        }
    }
    var str = "foobar";

    var a1 = Helper.create<A>(A, {data: str});
    expect(a1 instanceof A).toBeTruthy();
    expect(a1.data).toBe(str);

    var a2 = Helper.create(A, {data: str});
    expect(a2 instanceof A).toBeTruthy();
    expect(a2.data).toBe(str);

    var b1 = Helper.createRaw(B, {data: str});
    expect(b1 instanceof B).toBeTruthy();
    expect(b1.data).toBe(str);
    expect(b1.getData()).toBe(str);

});
   public clone<T>(sourceObj: T): T {
      var cloneObj: T = {} as T;
      for (var key in sourceObj) {
         if (sourceObj[key] instanceof Array) {
            if (sourceObj[key]) {
               // create an empty value first
               let str: string = '{"' + key + '" : ""}';
               Object.assign(cloneObj, JSON.parse(str))
               // update with the real value
               cloneObj[key] = sourceObj[key];
            } else {
               Object.assign(cloneObj, [])
            }
         } else if (typeof sourceObj[key] === "object") {
            cloneObj[key] = this.clone(sourceObj[key]);
         } else {
            if (cloneObj.hasOwnProperty(key)) {
               cloneObj[key] = sourceObj[key];
            } else { // insert the property
               // need create a JSON to use the 'key' as its value
               let str: string = '{"' + key + '" : "' + sourceObj[key] + '"}';
               // insert the new field
               Object.assign(cloneObj, JSON.parse(str))
            }
         }
      }
      return cloneObj;
   }
  let newObj: SomeClass = clone<SomeClass>(someClassObj);
export class TableComponent<T> {

    public Data: T[] = [];

    public constructor(
        protected type: new (value: Partial<T>) => T
    ) { }

    protected insertRow(value: Partial<T>): void {
        let row: T = new this.type(value);
        this.Data.push(row);
    }
}
export class MyDataComponent extends TableComponent<VW_MyData> {

    public constructor(protected service: DataService) {
        super(VW_MyData);
        this.query();
    }

    protected query(): void {
        this.service.post(...).subscribe((json: VW_MyData[]) => {
            for (let item of json) {
                this.insertRow(item);
            }
        }
    }
}
export class VW_MyData {
    
    public RawColumn: string;
    public TransformedColumn: string;


    public constructor(init?: Partial<VW_MyData>) {
        Object.assign(this, init);
        this.TransformedColumn = this.transform(this.RawColumn);
    }

    protected transform(input: string): string {
        return `Transformation of ${input}!`;
    }
}
class Sample {
    public innerField: string;

    constructor(data: Partial<Sample>) {
        this.innerField = data.innerField;
    }
}

export class GenericWithParams<TType> {
    public innerItem: TType;

    constructor(data: Partial<GenericWithParams<TType>>, private typePrototype: new (i: Partial<TType>) => TType) {
        this.innerItem = this.factoryMethodOnModel(data.innerItem);
    }

    private factoryMethodOnModel = (item: Partial<TType>): TType => {
        return new this.typePrototype(item);
    };
}

const instance = new GenericWithParams<Sample>({ innerItem : { innerField: 'test' }}, Sample);