Reputation: 426
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
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
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
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