A lightweight, partial implementation of the TC39 Reflect Metadata proposal. This library provides reflection metadata functionality with a focus on performance and bundle size.
- πͺΆ Lightweight: Only ~3.2KB unminified, 1.7KB minified, 0.7KB gzipped
- π Performance optimized: WeakMap-based storage for optimal memory usage
- π§ Function-activated: Extends the global Reflect object with metadata APIs
- π‘οΈ Safe: Won't override existing reflect-metadata implementations
- π¦ ESM native: Built for modern JavaScript environments
- π― TypeScript ready: Full type definitions included
npm install @arcmantle/reflect-metadatapnpm add @arcmantle/reflect-metadatayarn add @arcmantle/reflect-metadataExtend the global Reflect object with metadata APIs:
import { useReflectMetadata } from '@arcmantle/reflect-metadata';
// Extend the global Reflect with metadata APIs
const Reflect = useReflectMetadata();
// Now you can use Reflect metadata APIs (global Reflect is extended)
Reflect.defineMetadata('custom:key', 'value', target);
const value = Reflect.getMetadata('custom:key', target);<script type="module">
import { useReflectMetadata } from '@arcmantle/reflect-metadata';
const Reflect = useReflectMetadata();
// Reflect metadata APIs are now available globally
</script>This library implements the following Reflect metadata APIs:
Defines metadata for a target object or property.
const Reflect = useReflectMetadata();
Reflect.defineMetadata('custom:type', 'string', MyClass, 'propertyName');Retrieves metadata from a target object or property, including inherited metadata.
const Reflect = useReflectMetadata();
const type = Reflect.getMetadata('custom:type', MyClass, 'propertyName');Retrieves own metadata from a target object or property (no inheritance).
const Reflect = useReflectMetadata();
const ownType = Reflect.getOwnMetadata('custom:type', MyClass, 'propertyName');Checks if metadata exists for a target object or property (including inherited).
const Reflect = useReflectMetadata();
const hasType = Reflect.hasMetadata('custom:type', MyClass, 'propertyName');Checks if own metadata exists for a target object or property (no inheritance).
const Reflect = useReflectMetadata();
const hasOwnType = Reflect.hasOwnMetadata('custom:type', MyClass, 'propertyName');Creates a metadata decorator function.
const Reflect = useReflectMetadata();
const Type = (type: string) => Reflect.metadata('custom:type', type);
class MyClass {
@Type('string')
propertyName: string;
}Applies decorators to a target.
const Reflect = useReflectMetadata();
const decoratedClass = Reflect.decorate([MyDecorator], MyClass);import { useReflectMetadata } from '@arcmantle/reflect-metadata';
const Reflect = useReflectMetadata();
class User {
name: string;
email: string;
}
// Store metadata
Reflect.defineMetadata('validation:required', true, User, 'name');
Reflect.defineMetadata('validation:email', true, User, 'email');
// Retrieve metadata
const isNameRequired = Reflect.getMetadata('validation:required', User, 'name');
const isEmailValidation = Reflect.getMetadata('validation:email', User, 'email');import { useReflectMetadata } from '@arcmantle/reflect-metadata';
const Reflect = useReflectMetadata();
// Create a validation decorator
function Required(target: any, propertyKey: string) {
Reflect.defineMetadata('validation:required', true, target, propertyKey);
}
function Email(target: any, propertyKey: string) {
Reflect.defineMetadata('validation:email', true, target, propertyKey);
}
class User {
@Required
name: string;
@Required
@Email
email: string;
}
// Validation logic
function validate(instance: any) {
const constructor = instance.constructor;
for (const property of Object.keys(instance)) {
const isRequired = Reflect.getMetadata('validation:required', constructor, property);
const isEmail = Reflect.getMetadata('validation:email', constructor, property);
if (isRequired && !instance[property]) {
throw new Error(`${property} is required`);
}
if (isEmail && !instance[property].includes('@')) {
throw new Error(`${property} must be a valid email`);
}
}
}- Safe activation: Multiple calls to
useReflectMetadata()return the same extended global Reflect - Non-destructive: Won't override existing reflect-metadata implementations
- Global extension: Extends the global Reflect object with metadata methods
- ESM only: This package is ESM-only and requires Node.js 14+ or modern browsers
- Partial implementation: Only implements the most commonly used metadata APIs
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
- TC39 Reflect Metadata Proposal
- reflect-metadata - Full implementation