7

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!!

4
  • My guess is that you need to do obj.dataObject().myCoolProperty because the generated javascript is probably making your public get property a function. Commented Apr 3, 2015 at 17:44
  • I'm fairly confident that this code: this.dataObject = <T> new Object(); Doesn't actually create a new instance of the generic. The debugger shows dataObject as an empty Object. Commented Apr 3, 2015 at 17:56
  • sorry I got the wrong idea when reading that initially. There is this that might help you: stevefenton.co.uk/Content/Blog/Date/201407/Blog/… Commented Apr 3, 2015 at 18:10
  • Possible duplicate of How to create a new object from type parameter in generic class in typescript? Commented Dec 23, 2016 at 0:01

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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

1 Comment

This would work, just requires a little more code every time I extend the ProxyObject. The solution I posted is a little simpler IMHO. It's just too bad there's not an easy way to get a new instance of a Generic Type. Thanks!
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.