Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 350
Joe Firebaugh Avatar asked Apr 03 '15 17:04

Joe Firebaugh


People also ask

How do I create a generic class in TypeScript?

TypeScript supports generic classes. The generic type parameter is specified in angle brackets after the name of the class. A generic class can have generic fields (member variables) or methods. In the above example, we created a generic class named KeyValuePair with a type variable in the angle brackets <T, U> .

How do you define a generic object in TypeScript?

To specify generic object type in TypeScript, we can use the Record type. const myObj: Record<string, any> = { //... }; to set myObj to the Record type with string keys and any type for the property values.

Which construct is used to create generic classes or methods?

Like C++, we use <> to specify parameter types in generic class creation.


1 Answers

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.

like image 56
Titian Cernicova-Dragomir Avatar answered Sep 22 '22 08:09

Titian Cernicova-Dragomir