获取TypeScript

时间:2016-12-14 13:53:09

标签: typescript

class Test {
    @First()
    @Second()
    public someAttribute;
}

var t = new Test();
var decorators = t.getListOfAttributeDecorators("someAttribute");
console.log(decorators); // [First, Second]

我想实现" getListOfAttributeDecorators"功能,但不知道如何。或者有没有其他方法来获取属性修饰符列表?

2 个答案:

答案 0 :(得分:2)

您可以使用reflect-metadata获取有关自定义装饰器的数据。通过在decorator的实现中定义属性的元数据是可能的 -  see on codesandbox。您只能使用自定义装饰器执行此操作,但第三方库通常也使用此类方法使用不同的metadata key

// be sure to import reflect-metadata
// without importing reflect-metadata Reflect.defineMetadata and other will not be defined.
import "reflect-metadata";

function First(target: Object, propertyKey: string | symbol) {
  // define metadata with value "First"
  Reflect.defineMetadata("custom:anotations:first", "First", target, propertyKey);
}

function Second(target: Object, propertyKey: string | symbol) {
  // define metadata with value { second: 2 }
  // be sure that metadata key is different from First
  Reflect.defineMetadata("custom:anotations:second", { second: 2 }, target, propertyKey);
}

class Test {
  @First
  @Second
  someAttribute: string;
}

// get decorators

function getDecorators(target: any, propertyName: string | symbol): string[] {
  // get info about keys that used in current property
  const keys: any[] = Reflect.getMetadataKeys(target, propertyName);
  const decorators = keys
    // filter your custom decorators
    .filter(key => key.toString().startsWith("custom:anotations"))
    .reduce((values, key) => {
      // get metadata value.
      const currValues = Reflect.getMetadata(key, target, propertyName);
      return values.concat(currValues);
    }, []);

  return decorators;
}

// test

var t = new Test();
var decorators = getDecorators(t, "someAttribute"); // output is [{ second: 2}, "First"]
console.log(decorators);

不要忘记将"emitDecoratorMetadata": true添加到tsconfig.json,以便能够使用元数据进行操作。

奖励:class decorators支持实施 - see on codesandox

P.S。这是一个古老的问题,但是,我希望我的回答能帮助别人。

答案 1 :(得分:1)

您需要维护一个包含该信息的数据结构,例如:

const REGISTRY = new Map<string, Map<string, string[]>>();
function register(cls: string, property: string, decorator: string) {
    let map: Map<string, string[]>;

    if (REGISTRY.has(cls)) {
        map = REGISTRY.get(cls);
    } else {
        map = new Map<string, string[]>();
        REGISTRY.set(cls, map);
    }

    let list: string[];
    if (map.has(property)) {
        list = map.get(property);
    } else {
        list = [];
        map.set(property, list);
    }

    if (list.indexOf(decorator) < 0) {
        list.push(decorator);
    }
}

function First() {
    return function (cls: any, property: string) {
        register(cls.constructor.name, property, "First");
    }
}

function Second() {
    return function (cls: any, property: string) {
        register(cls.constructor.name, property, "Second");
    }
}

class Test {
    @First()
    @Second()
    public someAttribute;

    public getListOfAttributeDecorators(property: string): string[] {
        const name = this.constructor.name;
        return !REGISTRY.has(name) ? [] : REGISTRY.get(name).get(property);
    }
}

let t = new Test();
let names = t.getListOfAttributeDecorators("someAttribute");
console.log(names); // ["Second", "First"]

code in playground