Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a new object from type parameter in generic class

People also ask

Can you create an object of generic type?

A generic type is like a template. You cannot create instances of it unless you specify real types for its generic type parameters. To do this at run time, using reflection, requires the MakeGenericType method.

How can we create object for generic class?

Like C++, we use <> to specify parameter types in generic class creation. To create objects of a generic class, we use the following syntax. Note: In Parameter type we can not use primitives like 'int','char' or 'double'.

Can you create instances of generic type parameters?

Cannot Instantiate Generic Types with Primitive Types. Cannot Create Instances of Type Parameters.

How do I create a new object in TypeScript?

Syntax. var object_name = { key1: “value1”, //scalar value key2: “value”, key3: function() { //functions }, key4:[“content1”, “content2”] //collection }; As shown above, an object can contain scalar values, functions and structures like arrays and tuples.


To create a new object within generic code, you need to refer to the type by its constructor function. So 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 this:

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

var classA: ClassA = activator(ClassA);

See this question: Generic Type Inference with Class Argument


Because the compiled JavaScript has all the type information erased, you can't use T to new up an object.

You can do this in a non-generic way by passing the type into 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 could extend this example using generics to tighten up the 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();

All type information is erased in JavaScript side and therefore you can't new up T just like @Sohnee states, but I would prefer having typed parameter passed in to constructor:

class A {
}

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

var test = new B<A>(A);

export abstract class formBase<T> extends baseClass {

  protected item = {} as T;
}

Its object will be able to receive any parameter, however, type T is only a typescript reference and can not be created through a constructor. That is, it will not create any class objects.


I know late but @TadasPa's answer can be adjusted a little by using

TCreator: new() => T

instead of

TCreator: { new (): T; }

so the result should look like this

class A {
}

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

var test = new B<A>(A);

I was trying to instantiate the generic from within a base class. None of the above examples worked for me as they required a concrete type in order to call the factory method.

After researching for awhile on this and unable to find a solution online, I discovered that this appears to work.

 protected activeRow: T = {} as T;

The pieces:

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

...

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

All together

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

That said, 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();