Ori Refael
Ori Refael

Reputation: 3018

Typescript (Angular2) generic constructor factory

Im using typescipt 2. Im writing some parser method which receives a model from the server and converts it to an instance I can use.

Code:

export interface Constructable {
     copy(other : any) : void;
}

//in my Convert class which converts server responses to model
private static _parseT<T extends Constructable>(obj : any) : T {
    let instance = Object.create(T); // the row of the compile-time error
    instance.constructor.apply(instance);
    instance.copy(obj);
    return instance;
}

and lets assume I have the following class

export class Foo implements  Constructable {
    private test : string  = null;

    public copy(other:any) : void {
        this.test = other.test;
    }
}

I have a compile time error

Could not find name T

now, Im sure its not the syntax but I couldn't find how.

To clear things out. this is how the useage looks like:

public static ParseFoo(data: any) : Foo{
    return Convert._parseT<Foo>(data.mResult); // data is a server response object
}

NOTE

Although some factory pattern would solve this, I would really like to stay with the Copy method instead of some Generate which creates and returns an instance

Upvotes: 1

Views: 405

Answers (1)

Supamiu
Supamiu

Reputation: 8731

You get this error because T is a type, not a class.

A class in typescript has this signature: new(...args: any[]) => any and you can call Object.create on it, since T isn't a variable in your function you can't do such a thing.

To achieve what you want to do, you have to pass the class itself as argument:

private static _parseT<T extends Constructable>(clazz: new(...args: any[]) => any, obj : any) : T {
    let instance = <Constructable>new clazz();
    instance.copy(obj);
    return <T>instance;
}

This way, the only clazz that will be accepted is the one that constructs your type.

You can have an example on something I made recently on github (not an angular project but your issue is a pure typescript issue).

An example call for this function:

let FooInstance = this._parseT<FooClass>(FooClass, myObj);

Here, the first FooClass is the type, while the seconde one reefers to the class itself.

Since you can't get the class of a type at runtime, it's the only olution for you to construct a class from its type.

Upvotes: 2

Related Questions