Pytanie Jak utworzyć nowy obiekt z parametru typu w klasie ogólnej w maszynopisie?


Próbuję utworzyć nowy obiekt parametru typu w mojej klasie ogólnej. W mojej klasie "Widok" mam 2 listy obiektów typu ogólnego przekazanych jako parametry typu, ale kiedy próbuję wykonać new TGridView() maszynopis mówi Could not find symbol 'TGridView'...

To jest kod:

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

Czy mogę tworzyć obiekty z rodzaju ogólnego?


76
2018-06-29 16:10


pochodzenie




Odpowiedzi:


Ponieważ skompilowany JavaScript ma usunięte wszystkie informacje o typie, nie można go użyć T aby ulepszyć obiekt.

Możesz to zrobić w ogólny sposób, przekazując typ do konstruktora.

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

Możesz rozszerzyć ten przykład, używając generycznych do zaostrzenia typów:

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

51
2018-06-29 19:16



To jest super czyste i działa fantastycznie! - Jaume Mussons Abad


Aby utworzyć nowy obiekt w kodzie generycznym, musisz odwołać się do typu według jego funkcji konstruktora. Zamiast więc pisać to:

function activatorNotWorking<T extends IActivatable>(type: T): T {
    return new T(); // compile error could not find symbol T
}

Musisz napisać to:

function activator<T extends IActivatable>(type: { new(): T ;} ): T {
    return new type();
}

var classA: ClassA = activator(ClassA);

Zobacz to pytanie: Ogólne wnioskowanie typów z argumentem klasy


87
2017-11-02 05:52



Nieco spóźniony (ale użyteczny) komentarz - jeśli twój konstruktor przyjmuje argumenty to, to new() musi również - lub bardziej ogólny: type: {new(...args : any[]): T ;} - Rycochet
Co jest IActivatable? Nie mogę go znaleźć w żadnych dokumentach. - Yoda
@ Yoda IActivatable to własny interfejs, zobacz inne pytanie: stackoverflow.com/questions/24677592/... - Jamie


Wszystkie informacje o typach są wymazywane po stronie JavaScript i dlatego nie można dodawać T tak jak w @Sohnee, ale wolałbym mieć wpisany parametr do konstruktora:

class A {
}

class B<T> {
    Prop: T;
    constructor(TCreator: { new (): T; }) {
        this.Prop = new TCreator();
    }
}

var test = new B<A>(A);

15
2018-01-18 13:39





export abstract class formBase<T> extends baseClass {

  protected item = {} as T;
}

Obiekt może odbierać dowolny parametr, jednak typ T jest tylko referencją do maszynopisu i nie można go utworzyć za pomocą konstruktora. Oznacza to, że nie utworzy żadnych obiektów podklas.


7
2018-01-16 11:53



Proszę przeczytaj Jak odebrać i wyjaśnij, co robi ten kod. - CodeCaster
Strzec sięmoże to działać, ale wynikowy obiekt nie będzie typu T, więc zdefiniowane są wszystkie zmienne / setery T może nie działać. - Daniel Ormeño
@ DanielOrmeño staram się wyjaśnić? Co przez to rozumiesz? Mój kod wydaje się działać przy użyciu tego fragmentu. Dzięki. - eestein
JavaScript jest językiem interpretowanym, a ecmascript nie ma jeszcze odniesień do typów lub klas. Więc T jest po prostu odniesieniem do maszynopisu. - jalescardoso


używam tego: let instance = <T>{}; na ogół działa EDYCJA 1:

export class EntityCollection<T extends { id: number }>{
  mutable: EditableEntity<T>[] = [];
  immutable: T[] = [];
  edit(index: number) {
    this.mutable[index].entity = Object.assign(<T>{}, this.immutable[index]);
  }
}

0
2017-10-03 15:07



To faktycznie nie tworzy instancji nowej instancji T, po prostu zrobi pusty obiekt TypeScript myśli jest typu T. Możesz wyjaśnić swoją odpowiedź nieco bardziej szczegółowo. - Sandy Gifford
Powiedziałem, że to na ogół działa. Jest dokładnie tak, jak mówisz. Kompilator nie marudzi i masz ogólny kod. Możesz użyć tej instancji do ręcznego ustawienia żądanych właściwości bez potrzeby jawnego konstruktora. - Bojo


Próbowałem utworzyć instancje generyczne z poziomu klasy bazowej. Żaden z powyższych przykładów nie zadziałał, ponieważ wymagał konkretnego typu, aby wywołać metodę fabryczną.

Po badaniu przez chwilę i nie mogąc znaleźć rozwiązania w Internecie, odkryłem, że to działa.

 protected activeRow: T = {} as T;

Kawałki:

 activeRow: T = {} <-- activeRow now equals a new object...

...

 as T; <-- As the type I specified. 

Wszyscy razem

 export abstract class GridRowEditDialogBase<T extends DataRow> extends DialogBase{ 
      protected activeRow: T = {} as T;
 }

0
2017-10-09 22:54