typescriptgenerics

Create a new object from type parameter in generic class


I'm trying to create a new object of a type parameter in my generic class. In my class View, I have 2 lists of objects of generic type passed as type parameters, but when I try to make new TGridView(), TypeScript says:

Could not find symbol 'TGridView

This is the code:

module AppFW {
    // Represents a view
    export class View<TFormView extends FormView, TGridView extends GridView> {
        // The list of forms 
        public Forms: { [idForm: string]: TFormView; } = {};

        // The list of grids
        public Grids: { [idForm: string]: TGridView; } = {};

        public AddForm(formElement: HTMLFormElement, dataModel: any, submitFunction?: (e: SubmitFormViewEvent) => boolean): FormView {
            var newForm: TFormView = new TFormView(formElement, dataModel, submitFunction);
            this.Forms[formElement.id] = newForm;
            return newForm;
        }

        public AddGrid(element: HTMLDivElement, gridOptions: any): GridView {
            var newGrid: TGridView = new TGridView(element, gridOptions);
            this.Grids[element.id] = newGrid;
            return newGrid;
        }
    }
}

Can I create objects from a generic type?


Solution

  • Because the compiled JavaScript has all the type information erased, you can't use T to new up an object.

    You can do this in a non-generic way by passing the type into the constructor.

    class TestOne {
        hi() {
            alert('Hi');
        }
    }
    
    class TestTwo {
        constructor(private testType) {
    
        }
        getNew() {
            return new this.testType();
        }
    }
    
    var test = new TestTwo(TestOne);
    
    var example = test.getNew();
    example.hi();
    

    You could extend this example using generics to tighten up the types:

    class TestBase {
        hi() {
            alert('Hi from base');
        }
    }
    
    class TestSub extends TestBase {
        hi() {
            alert('Hi from sub');
        }
    }
    
    class TestTwo<T extends TestBase> {
        constructor(private testType: new () => T) {
        }
    
        getNew() : T {
            return new this.testType();
        }
    }
    
    //var test = new TestTwo<TestBase>(TestBase);
    var test = new TestTwo<TestSub>(TestSub);
    
    var example = test.getNew();
    example.hi();