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

Reflection TypeScript-将类作为参数传递,并进行反射,reflection,typescript,marshalling,unmarshalling,Reflection,Typescript,Marshalling,Unmarshalling,我正在写一个通用的解组器。它将图形数据库数据转换为生成的TypeScript(1.8.7)模型类。输入是JSON。输出应该是模型类的实例。 我的最终目标是创建像Hibernate OGM这样的东西,只适用于TIKEPOP框架和TypeScript,中间有REST端点。 将类作为参数传递并到达其静态成员的正确方法是什么?我希望有如下内容: SomeModel some = <SomeModel> unmarshaller.fromJSON({/*Object from JSON*/},

我正在写一个通用的解组器。它将图形数据库数据转换为生成的TypeScript(1.8.7)模型类。输入是JSON。输出应该是模型类的实例。
我的最终目标是创建像Hibernate OGM这样的东西,只适用于TIKEPOP框架和TypeScript,中间有REST端点。

将类作为参数传递并到达其静态成员的正确方法是什么?我希望有如下内容:

SomeModel some = <SomeModel> unmarshaller.fromJSON({/*Object from JSON*/}, SomeModel);
/**
 * 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;
    }
}
但当我试图在Plunker上执行此操作时,我得到了执行错误和无用的stacktrace

模型超类如下所示:

SomeModel some = <SomeModel> unmarshaller.fromJSON({/*Object from JSON*/}, SomeModel);
/**
 * 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实现这一点。

我知道我可能会使用装饰器获得类似的结果,但对于生成的模型,使用字段或静态字段似乎更简单。

您可能已经注意到类成员不能使用
const
关键字。但是您可以使用
static
。此外,若你们想从外部世界访问它,那个么成员应该是公共的

public static graphPropertyMapping: { [key:string]:string; } = {
    bar: 'boo',
    name: 'name',
    rank: 'rank',
};
关于创建结果实例:

let result = new clazz();

//copy properties

return result;

如果我理解正确,那么这里有一些东西可以帮助您开始:

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);
    }
}
接口模型{}
接口模型数据{}
接口MyModelConstructor{
新(数据:D):M;
//静态成员
graphPropertyMapping:任意;
graphRelationMapping:任何;
}
类解组器{
public-fromJSON(输入:string | ModelData,ctor:MyModelConstructor):T{
let data:ModelData=(typeof input==“string”)?JSON.parse(input):input;
设propertyMapping=ctor.graphPropertyMapping;
让relationMapping=ctor.graphRelationMapping;
//对映射执行任何操作
返回新的ctor(输入);
}
}
()


我不知道您的模型是什么样子,所以我希望这已经足够接近了。

我最近发布了一个增强版的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());
当然,如果您将clazz的
成员
属性访问更改为
静态
,您将检索所有静态成员。这些信息也可以在编码时访问,所以您可以使用自动补全。 您可以对接口元数据执行相同的操作。例如,只需编写
MyInterface
,并访问其成员。
你可以找到这个项目。

调用
类是很传统的做法。
klass:)对,上面的例子是手工编写的,所以包含了这些错误。我真的很想知道TypeScript是如何实现和限制“静态”的——因为在JavaScript中,没有什么是真正静态的,它是绑定到函数的。从技术上讲,如果你从一个函数继承,我猜类继承是如何在TS中完成的,你也继承了静态字段吗?因此,
MyClass.staticField
在技术上也可以作为
MySubclass.staticField
访问?除非TS坚持Java的
static
…是
MyClass.staticField
也可以作为
MySubclass.staticField
访问。您是对的,它绑定到函数(类定义),这看起来很合理。能否请您添加一些链接,说明接口需求背后的基本原理?我的意思是,在Java中,不需要接口来检查类元数据和注释。这是一种“官方”方式还是利用某些副作用?谢谢你的打字脚本,你不必使用它们,但它是有意义的。在我的示例中,我没有使用元数据或注释,这里唯一的东西是表示对类的引用(而不是对实例的引用)的接口:
MyModelConstructor
。如果你能更具体地说明你想知道什么,我会修改我的答案以适应这个问题。我对你的例子理解得更多一些。看起来您建议每个模型都有一个构造函数类。即,每个模型都有各自的构造函数类。因为我生成了模型,所以我更希望只有一个服务类能够利用模型类中的JSON数据和元数据构建模型。我想我会改进我的问题代码。你不需要有不同的ctor类,你只需要一个,这取决于你。另外,你不需要我包含的泛型部分,在我看来这更容易,并且不需要在以后进行强制转换。但是,由于您没有包括如何创建这些模型的实例,我很难给您一个更具体的答案。我还没有创建实例。这是我还没有弄清楚的事情之一。我最初的想法是创建一个具有特定模型所需的相应属性的
对象
,然后对其进行强制转换。