Create a new object from a type parameter in a generic class

I am trying to create a new type parameter object in my generic class. In my View class, I have 2 lists of objects of a general type, passed as type parameters, but when I try to create a new TGridView() , TypeScript says:

Could not find character 'TGridView

This is the code:

 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; } } } 

Can I create objects from a generic type?

+102
generics typescript
Jun 29 '13 at 16:10
source share
8 answers

Since compiled JavaScript has all the type information, you cannot use T for a new object.

You can do this in a non-general way by passing this type to the constructor.

 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(); 

You can extend this example with generics to tighten types:

 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(); 
+63
Jun 29 '13 at 19:16
source share
β€” -

To create a new object in shared code, you need to access the type using its constructor function. Therefore, instead of writing this:

 function activatorNotWorking<T extends IActivatable>(type: T): T { return new T(); // compile error could not find symbol T } 

You need to write the following:

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

See this question: General type inference with class argument

+110
Nov 02 '14 at 5:52
source share

All type information is erased by JavaScript, so you cannot create new T in the same way as @Sohnee states, but I would prefer this parameter to be introduced into the constructor:

 class A { } class B<T> { Prop: T; constructor(TCreator: { new (): T; }) { this.Prop = new TCreator(); } } var test = new B<A>(A); 
+26
Jan 18 '16 at 1:39 on
source share
 export abstract class formBase<T> extends baseClass { protected item = {} as T; } 

Its object will be able to accept any parameter, however type T is only a reference to typewritten text and cannot be created using the constructor. That is, it will not create any class objects.

+7
Jan 16 '17 at 11:53 on
source share

I tried to create an instance from the base class. None of the above examples worked for me, as they needed a specific type to call the factory method.

After some research on this issue and the inability to find a solution on the Internet, I found that it works.

  protected activeRow: T = {} as T; 

Pieces:

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

...

  as T; <-- As the type I specified. 

Together

  export abstract class GridRowEditDialogBase<T extends DataRow> extends DialogBase{ protected activeRow: T = {} as T; } 

However, if you need an actual instance, you should use:

 export function getInstance<T extends Object>(type: (new (...args: any[]) => T), ...args: any[]): T { return new type(...args); } export class Foo { bar() { console.log("Hello World") } } getInstance(Foo).bar(); 

If you have arguments, you can use.

 export class Foo2 { constructor(public arg1: string, public arg2: number) { } bar() { console.log(this.arg1); console.log(this.arg2); } } getInstance(Foo, "Hello World", 2).bar(); 
+1
Oct 09 '17 at 10:54 on
source share

i use this: let instance = <T>{}; it generally works EDIT 1:

 export class EntityCollection<T extends { id: number }>{ mutable: EditableEntity<T>[] = []; immutable: T[] = []; edit(index: number) { this.mutable[index].entity = Object.assign(<T>{}, this.immutable[index]); } } 
0
Oct 03 '17 at 15:07 on
source share

I do not quite answer the question, but there is a good library for such problems: https://github.com/typestack/class-transformer (although it will not work for generic types, since they do not actually exist at runtime (here all work is done with class names (which are class constructors)))

For example:

 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 
0
May 11 '19 at 20:08
source share

In Typescript, I used Object to resolve both the "single object" type and the "Array of object" type

 public class A<T> { public Data:T = new Object() as T; } 
-2
Apr 23 '19 at 16:45
source share



All Articles