106

what are reflect-metadata and its purpose?

What is syntax and purpose of using reflect-metadata?

Can some one provide the example for better understanding of the same?

How can be the reflect metadata helpful in implementing decorators in typescript.

Mantu Nigam
  • 3,690
  • 7
  • 24
  • 41
  • 2
    This link might help http://blog.wolksoftware.com/decorators-metadata-reflection-in-typescript-from-novice-to-expert-part-4 – Shiljo Paulson Jul 17 '17 at 04:24

2 Answers2

92

reflect-metadata Allows you to do runtime reflection on types.

The native (non reflect-metadata) version of type inference is much poorer than reflect-metadata and consists only of typeof and instanceof.

More

This blog post covers its features well : http://blog.wolksoftware.com/decorators-metadata-reflection-in-typescript-from-novice-to-expert-part-4

basarat
  • 261,912
  • 58
  • 460
  • 511
  • 2
    @barasat Is it the reflection or just Dictionary with key and value pair with some other params like Serializer and Constructor type? – Mantu Nigam Jul 17 '17 at 11:13
  • 2
    @MantuNigam just a dictionary built from the type definition (instead of runtime value assignments) – basarat Jul 17 '17 at 23:38
  • Should this be imported everywhere where we are using decorators that use the `Reflect` API? Or is there a way to make `tsc` import it only once for the entire project? – CMCDragonkai Aug 14 '22 at 13:46
2

One way of using standard Reflect functionality with decorators:

import { performance } from 'perf_hooks';

// common decorator
export function log() {
    return (_target, propertyKey: string, descriptor: PropertyDescriptor) => {
        const originalMethod = descriptor.value;

        descriptor.value = async function (...args) {
            const start = performance.now();

            const result = await originalMethod.apply(this, args);

            const finish = performance.now();

            const ms = Math.round(finish - start);
            console.log(`[${propertyKey}] ${ms}ms`);

            return result;
        };

        return descriptor;
    };
}

// Decorator to log class method or all class methods with Reflect
export function Log(): MethodDecorator & ClassDecorator {
    return (target: any, key?: string, descriptor?: TypedPropertyDescriptor<any>) => {
        if (descriptor) {
            // method decorator
            return log()(target, key, descriptor);
        }

        const methodNames = Reflect.ownKeys(target.prototype);
        methodNames.forEach((methodName: string) => {
            if (methodName !== 'constructor') {
                const methodDescriptor = Reflect.getOwnPropertyDescriptor(target.prototype, methodName);

                const modifiedMethodDescriptor = log()(target, methodName, methodDescriptor);

                Reflect.defineProperty(target.prototype, methodName, modifiedMethodDescriptor);
            }
        });

        // class decorator
        return target;
    };
}

Example:

@Log() // set logging for all Service class methods
class Service {
  @Log() // set logging only for this method
  handleTasks() {}
}

Reflect Documantation

zemil
  • 3,235
  • 2
  • 24
  • 33