Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to constraint a generic type to have new()?

Tags:

typescript

I want to have a function like:

createEntity<TEntity>(): TEntity {
    return new TEntity();
}

In C#, we could write:

void TEntity CreateEntity<TEntity>() where TEntity : new()

How can I do this in TypeScript?

like image 639
mehrandvd Avatar asked Jan 09 '16 20:01

mehrandvd


People also ask

How do you add generic constraints?

You can specify one or more constraints on the generic type using the where clause after the generic type name. The following example demonstrates a generic class with a constraint to reference types when instantiating the generic class.

What does where T new () mean?

where T : new() Means that the type T must have a parameter-less constructor. Having this constraint will allow you to do something like T field = new T(); in your code which you wouldn't be able to do otherwise. You then combine the two using a comma to get: where T : class, new()

What keyword allows you to put constraints on a generic type?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function.

What is generic type constraint?

A type constraint on a generic type parameter indicates a requirement that a type must fulfill in order to be accepted as a type argument for that type parameter. (For example, it might have to be a given class type or a subtype of that class type, or it might have to implement a given interface.)


2 Answers

The only way shown in the handbook to do something similar to this is to send the class you want to initialize as a parameter to the factory method, and describe it's constructor using the new keyword.

function factory<T>(type: { new (): T }): T {
    return new type();
}

class SomeClass { }

let result = factory(SomeClass);

The result will be of type SomeClass.

The constructor of the class will be type checked against the interface defined in the factory method.

If you want to initialize a class that takes a parameter in it's constructor you will have to specify that in the interface given to the factory method.

function factory<T>(type: { new (...args): T }, ...args): T {
    return new type(...args);
}


class SomeClass {
    constructor(name: string) { }
}

let a = factory(SomeClass, 'John Doe');
like image 113
toskv Avatar answered Oct 05 '22 07:10

toskv


This has been answered here in Stack Overflow. To be able to new up a new class using generics, you need to have a guarantee that the type supports instantiation.

You can easily support parameter less constructors using this approach but with constructors that require parameters, it would become less useful as your creatEntity method should have to accept the values for those parameters and pass to the constructor while creating the new instance and as you can see each type can have its own signature for constructor.

class ObjectCreator{
    static createEntity<TEntity>(type:{new():TEntity;}):TEntity{
        return new type();
    }
}

class Person{
    firstName:string;
    lastName:string;
    constructor(){
        this.firstName = "TestFirstName";
        this.lastName = "TestLastName";
    }
}

var person: Person = ObjectCreator.createEntity(Person);
alert(person.firstName);
like image 42
Seshu Kumar Alluvada Avatar answered Oct 05 '22 08:10

Seshu Kumar Alluvada