如何在TypeScript中像Java一样使用反射?

6

我在Java中使用反射来获取TestNG注释中的一些信息,就像下面的代码片段中所示:

Reflections reflections = new Reflections("", new MethodAnnotationsScanner())
Set<Method> annotated = reflections.getMethodsAnnotatedWith(Test.class)

目前,我有一个带有jest装饰器插件的jest框架,以帮助使用注释。

我如何在typescript中复制相同的反射方法,以从注释中收集这些信息?


你想要获取 java 类的标注信息的 JavaScript 代码? 我认为这是不可能的。 - f1sh
抱歉,TypeScript - johny
2个回答

3
请看Typescript的装饰器 + 反射元数据API,这也可以在TS编译器中启用。它不完全像Java,但您仍然可以收集有关已注释实体的所需信息。以下是如何收集已注释类的简单示例:
const myTypes: any[] = []

@annotation
class MyClass {
  type = "report";
  title: string;
 
  constructor(t: string) {
    this.title = t;
  }
}

function annotation(constructor: Function) {
    myTypes.push(constructor)
}

console.log('All annotated classes', myTypes);


2

试一下tst-reflect。 这是一款很高级的TypeScript反射系统(使用自定义TypeScript转换器插件)。

这应该等同于您的Java代码:

import {
    reflect,
    Type
} from "tst-reflect";

// Some decorator...
function test(_, __)
{
}

@reflect()
class A
{
    @test
    foo()
    {
        return 0;
    }

    bar()
    {
        return "lorem ipsum";
    }
}

@reflect()
class B
{
    @test
    bar()
    {
        return "lorem ipsum";
    }
}

@reflect()
class C
{
    baz()
    {
        return "lorem ipsum";
    }
}

const decoratedMethods = Type.getTypes()
    .flatMap(type => type.getMethods().map(method => ({ method, type })))
    .filter(entry => entry.method.getDecorators().some(decorator => decorator.name == "test"));

for (let entry of decoratedMethods)
{
    console.log(entry.method.name, "in", entry.type.name);
}

输出

foo in A
bar in B

请检查概要。 您可以创建这些类型的实例(即使它们来自不同的文件),并调用这些方法。 此外,这些装饰器可以带有参数,因此您将能够使用具有相同装饰器但不同参数的方法进行过滤。

tst-reflect仍在开发中,因此全局类型查找需要那些@reflect装饰器或带有@reflect JSDoc标签的自定义装饰器;原因是生成的元数据的大小优化。但是有一个问题可以通过“包含” glob 模式来扩展配置,这将包括由该 glob 匹配的所有模块中的所有类型。

附言:请查看配置维基并使用此配置:

tsconfig.json

{
    "compilerOptions": {
        // your options...

        // ADD THIS!
        "plugins": [
            {
                "transform": "tst-reflect-transformer"
            }
        ]
    },
    // ADD THIS!
    "reflection": {
        "metadata": {
            "type": "typelib" // this mode will generate and auto-import library with generated reflection metadata
        }
    }
}

使用反射,我能否在接口字段上注释装饰器?例如,我在我的接口IMyInterface中有一个field1字段。我想在IMyInterface的field1字段中添加@ApiProperty装饰器(类似于@ApiProperty field1:boolean)。 使用反射是否可能实现这一点? - Pradip
1
@Pradip 不行,您无法在接口内部修饰任何内容。这是 TypeScript 不允许的。接口在运行时不存在,因此您没有任何东西可以修饰。您必须使用例如抽象类。 - Hookyns
好的。假设我将接口实现为一个类(class MyClass implements IMyInterface),那么我能否在MyClass的每个属性上添加@ApiProperty装饰器? - Pradip
function ApiProperty(targetPrototype: Object, propertyKey: string | symbol) { /* 做些什么,或者不做... */ } class MyClass implements IMyInterface { @ApiProperty myprop: string; }你需要在tsconfig.json文件中启用装饰器。 - Hookyns
谢谢。我的问题是: 我能否使用Typescript反射在MyClass的每个字段中添加@ ApiPropery装饰器。MyClass实现了IMyInterface。 - Pradip
你的意思是动态的吗?装饰器只是一个函数,所以你可以手动调用它。getType<MyClass>().getProperties().forEach(prop => ApiProperty(MyClass.prototype, prop.name))但是你可能需要设置reflect-metadata,这取决于你想做什么以及装饰器来自哪里。 - Hookyns

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接