Joe Firebaugh
Joe Firebaugh

Reputation: 426

How can I create a new instance of the generic type of my Typescript class?

How can I make the following work as expected in Typescript?

export class ProxyObject<T> {
    private _dataObject:T;
    constructor(dataObject?:T) {
        if (dataObject) {
            this.dataObject = dataObject;
        } else {
            //create a new instance of the generic <T> here
            this.dataObject = <T> new Object();
        }
    }
    set dataObject(dataObject:T) {
        this._dataObject = dataObject;
    }
    get dataObject():T {
        return this._dataObject;
    }
}

export class ClassA {
   myCoolProperty = "My Cool Property";
}

When I do the following:

export class MyObject extends ProxyObject<ClassA> {
}

And then:

var obj = new MyObject();
obj.dataObject.myCoolProperty === undefined

None of the ClassA properties or functions exist on the dataObject inside the MyObject as I was expecting. For instance, I expected dataObject to have myCoolProperty.

I'm trying to write a ProxyObject class that when extended it's DataObject storage is typed as the generic.

Thanks!!

Upvotes: 7

Views: 10885

Answers (3)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250366

Since typescript generics are implemented using type erasure T is not present at runtime, you can however pass the class in as a parameter to the base class constructor and then use it to create the new object.

export class DataObjectBase {
}

export class ProxyObject<T extends DataObjectBase> {
    private _dataObject: T;
    constructor(dataObject?: T, cls?: typeof DataObjectBase) {
        if (dataObject) {
            this.dataObject = dataObject;
        } else {
            //create a new instance of the generic <T> here
            this.dataObject = <T> new cls();
        }
    }
    set dataObject(dataObject: T) {
        this._dataObject = dataObject;
    }
    get dataObject(): T {
        return this._dataObject;
    }
}



export class ClassA {
    myCoolProperty = "My Cool Property";
}


export class MyObject extends ProxyObject<ClassA> {
    public constructor(dataObject?: ClassA) {
        super(dataObject, ClassA);
    }
}

new MyObject();
obj.dataObject.myCoolProperty !== undefined

This approach still requires a bit of code in the derived classes but at least it keeps all of the logic in the base class

The class DataObjectBase is necessary since if I would have used typeof Object instead, ClassA could not have fulfilled the signarure of the Object class (as in ClassA doesn't have the constructors Object has). DataObjectBase is a class with a single constructor with no arguments, which ClassA, although not explicitly deriving from it, fulfills.

Upvotes: 4

Joe Firebaugh
Joe Firebaugh

Reputation: 426

I am open to some cooler answers to this question, but for now I just added a method that needs to be overloaded to return a new instance of the Generic.

export class ProxyObject<T> {

    private _dataObject:T;

    constructor(dataObject?:any) {
        if (dataObject) {
            this.dataObject = dataObject;
        } else {
            this.dataObject = this.createEmptyDataObject();
        }
    }

    protected createEmptyDataObject():T {
        throw new Error('You must overload the createEmptyDataObject() method on ProxyObject');
        return null;
    }

    set dataObject(dataObject:T) {
        this._dataObject = dataObject;
    }

    get dataObject():T {
        return this._dataObject;
    }
}

For instance, this is an example:

export class TabularRecord extends ProxyObject<TabularRecordDO> {

    createEmptyDataObject():TabularRecordDO {
        return new TabularRecordDO();
    }

    get record():any {
        return this.dataObject.record;
    }

    set record(record:any) {
        this.dataObject.record = record;
    }
}

Upvotes: 0

Paleo
Paleo

Reputation: 23772

The <T> new Object() doesn't create an instance of T. Try this:

class MyObject extends ProxyObject<ClassA> {
    constructor(dataObject?: ClassA) {
        if (dataObject) {
              super(dataObject);
          } else {
              //create a new instance of the generic <T> here
              super(new ClassA());
          }
    }
}

Upvotes: 0

Related Questions