TypeScript - trecerea unei clase ca argument și reflecția


Scriu un unmarshaller generic. Acesta convertește datele dintr-o bază de date graf către clase de model TypeScript (1.8.7) generate. Intrarea este JSON. Ieșirea ar trebui să fie o instanță a unei clase de model.
Scopul meu final este să creez ceva de genul Hibernate OGM, doar că pentru Tinkerpop Frames și TypeScript, cu un endpoint REST în mijloc.

Care este modul corect de a trece o clasă ca parametru și de a accesa membrii săi statici? Vreau să am ceva de genul acesta:

SomeModel some = <SomeModel> unmarshaller.fromJSON({/*Object from JSON*/}, SomeModel);

Am încercat să scriu o metodă. Nu sunt sigur dacă merg în direcția corectă, simte-te liber să sugerezi abordări diferite.

public fromJSON(input: Object, clazz: typeof FrameModel): FrameModel
{
    // This only demonstrates access to Framemodel's metadata 
    // about original Java model classes.
    clazz.graphPropertyMapping;
    clazz.graphRelationMapping;

    let result = {};
    ...
    return result;
}
...

Dar atunci când am încercat să execut acest lucru pe Plunker, am primit erori de execuție cu o urmărire a stivei inutilă.

Clasa superioară a modelului arată astfel:

/**
 * Things common to all Frames models on the Typescript side.
 */
export class FrameModel
{
    // Model metadata
    static discriminator: string;
    static graphPropertyMapping: { [key:string]:string; };
    static graphRelationMapping: { [key:string]:string; };

    // Each instance needs a vertex ID
    private vertexId: number;
    public getVertexId(): number {
        return this.vertexId;
    }
}

Exemplu de clasă model:

import {TestPlanetModel} from './TestPlanetModel';
import {TestShipModel} from './TestShipModel';

export class TestGeneratorModel extends FrameModel
{
    static discriminator: string = 'TestGenerator';
    static graphPropertyMapping: { [key:string]:string; } = {
        bar: 'boo',
        name: 'name',
        rank: 'rank',
    };
    static graphRelationMapping: { [key:string]:string; } = {
        colonizes: 'colonizedPlanet',
        commands: 'ship',
    };

    boo: string;
    name: string;
    rank: string;

    public colonizedPlanet: TestPlanetModel[]; // edge label 'colonizedPlanet'

    public ship: TestShipModel; // edge label 'ship'

}

Nu am găsit multe materiale despre reflecție și gestionarea claselor în TypeScript.
Știu cum aș face asta în Java.
Știu cum aș face asta în JavaScript.
Înțeleg că aș putea obține rezultate similare cu decoratori, dar a avea câmpuri sau câmpuri statice părea puțin mai simplu, pentru modelele generate.

Răspuns #1

Poate ați observat deja că membrii unei clase nu pot avea cuvântul cheie const. Dar ați putea folosi static în schimb. De asemenea, membrul ar trebui să fie public dacă doriți să fie accesibil din exterior.

public static graphPropertyMapping: { [key:string]:string; } = {
    bar: 'boo',
    name: 'name',
    rank: 'rank',
};

În ceea ce privește crearea unei instanțe de rezultat:

let result = new clazz();

//copy properties

return result;

Răspunsul #2

Dacă te înțeleg corect, atunci iată ceva care să te ajute să începi:

interface Model {}

interface ModelData {}

interface MyModelConstructor<M extends Model, D extends ModelData> {
    new(data: D): M;
    // static members
    graphPropertyMapping: any;
    graphRelationMapping: any;
}

class Unmarshaller {
    public fromJSON<T>(input: string | ModelData, ctor: MyModelConstructor<T, ModelData>): T {
        let data: ModelData = (typeof input === "string") ? JSON.parse(input) : input;

        let propertyMapping = ctor.graphPropertyMapping;
        let relationMapping = ctor.graphRelationMapping;

        // do whatever with the mappings

        return new ctor(input);
    }
}

(cod în teren de joacă)

Nu știu cum arată modelele voastre, așa că sper că acesta este suficient de aproape.