简体   繁体   中英

How to read instance decorators in typescript?

I can create custom decorator using reflect-metadata and it work fine.

Problem is, that I don`t know how to get all instance decorators.

import 'reflect-metadata';

console.clear();

function readTypes() {
  const decorator: MethodDecorator = (target, propertyKey, description) => {
    const args = Reflect.getMetadata(
      'design:paramtypes',
      target,
      propertyKey
    ).map(c => c.name);
    const ret = Reflect.getMetadata('design:returntype', target, propertyKey);
    console.log(`Arguments type: ${args.join(', ')}.`);
    console.log(`Return type:    ${ret.name}.`);
  };
  return decorator;
}

class Foo {}

class Bar {
  @readTypes()
  public fn(a: number, b: string, c: Foo): boolean {
    return true;
  }
}

const barInstance = new Bar();

I would like to get all functions with decorator @readTypes from barInstance . How can I do it?

See working example: https://stackblitz.com/edit/decorators-metadata-example-nakg4c

First of all, you aren't writing any metadata, only reading it. If you want to lookup which properties were decorated, then you have to write metadata to those properties.

For simplicity's sake, let's simplify the decorator to:

// It's a best practice to use symbol as metadata keys.
const isReadTypesProp = Symbol('isReadTypesProp')

function readTypes() {
  const decorator: MethodDecorator = (target, propertyKey, description) => {
    Reflect.defineMetadata(isReadTypesProp, true, target, propertyKey);
  };
  return decorator;
}

Now when the decorator is used, it's executed when the class is parsed, not when instances are created. This means that target in the decorator function is actually the prototype of the class constructor function.

In other words target is the same object as Bar.prototype or barInstance.constructor.prototype or barInstance.__proto__ .

Knowing that we can loop over all the property names in the prototype object and look up that metadata we set earlier:

function getReadTypesPropsFromInstance(object: {
  constructor: {
    prototype: unknown;
  };
}) {
  const target = object.constructor.prototype;
  const keys = Object.getOwnPropertyNames(target);
  return keys.filter(key => Reflect.getMetadata(isReadTypesProp, target, key));
}

Which now returns the names of the decorated properties:

const barInstance = new Bar();
console.log(getReadTypesPropsFromInstance(barInstance)); // ["fn"]

Working example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM