TypeScript - 将类作为参数传递,并将反射

时间:2016-07-27 22:55:39

标签: reflection typescript marshalling unmarshalling

我正在写一个通用的unmarshaller。它将图形DB数据转换为生成的TypeScript(1.8.7)模型类。输入是JSON。输出应该是模型类的实例 我的最终目标是创建类似Hibernate OGM的东西,仅用于Tinkerpop Frames和TypeScript,中间有REST端点。

将一个类作为参数传递给它的静态成员的正确方法是什么?我想要这样的东西:

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

我试过写一个方法。 不确定我是否朝着正确的方向前进,随意提出不同的方法。

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

但是当我尝试在Plunker上执行此操作时,我遇到了无用堆栈跟踪的执行错误。

模型超类看起来像这样:

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

样本模型类:

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'

}

我在TypeScript中找不到很多关于反射和类处理的材料 我知道如何用Java做到这一点 我知道如何在JavaScript中执行此操作 我知道我可能会使用装饰器获得类似的结果,但对于生成的模型,使用字段或静态字段似乎更简单。

3 个答案:

答案 0 :(得分:0)

您可能已经注意到,班级成员不能拥有const个关键字。但你可以选择static。如果您希望成员可以从外部访问,则该成员也应该是公开的。

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

至于创建结果实例:

let result = new clazz();

//copy properties

return result;

答案 1 :(得分:0)

如果我理解正确,那么这里可以帮助您入门:

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

code in playground

我不知道你的模特是什么样子的,所以我希望它足够接近。

答案 2 :(得分:0)

我最近发布了TypeScript编译器的增强版本,它可以准确地提供您所期望的内容:从类中读取所有(静态或非静态)字段元数据。例如,你可以写:

interface MyInterface {
    active:boolean;
    description: string;
}

class MyClass {
    id: number;
    name: string;
    myComplexField: MyInterface;
}

function printMembers(clazz: Class) {
    let fields = clazz.members.filter(m => m.type.kind !== 'function'); //exclude methods.
    for(let field of fields) {
        let typeName = field.type.kind;
        if(typeName === 'class' || typeName === 'interface') {
            typeName = (<Class | Interface>field.type).name;
        }
        console.log(`Field ${field.name} of ${clazz.name} has type: ${typeName}`);
    }
}

printMembers(MyClass.getClass());

这是输出:

$ node main.js
Field id of MyClass has type: number
Field name of MyClass has type: string
Field myComplexField of MyClass has type: MyInterface

当然,如果您将clazz的members属性访问权限更改为statics,您将检索所有静态成员。这些信息也可以在编码时访问,因此您可以使用自动完成功能。 您可以使用Interfaces元数据执行相同操作。只需编写MyInterface例如,并访问其成员。 您可以找到项目here