Metadata reflection based on TypeScript's experimental support for stage 2 decorators and metadata.
If you are unfamiliar with decorators and metadata, I recommend checking out the TypeScript documentation and TC39's decorator proposal documentation.
- https://www.typescriptlang.org/docs/handbook/decorators.html
- https://github.com/tc39/proposal-decorators
The following versions of Node.js and TypeScript are required:
- Node.js 20 or higher
- TypeScript 4.7 or higher
This package is pure ESM, and you must configure your project to use the ESM package.
npm install class-metadata
2. Set compiler options in your tsconfig.json
to enable experimental support for stage 2 decorators and metadata
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
You can read and write metadata of classes, class members, and parameters.
It is recommended to use the MetadataKey
class to handle metadata type-safely.
const EXAMPLE: MetadataKey<string> = new MetadataKey('example');
function Example(value: string): Decorator {
return MetadataReflector.createDecorator((metadata: Metadata): void => {
metadata.set(EXAMPLE, value);
});
}
@Example('foo')
class Greeter {
@Example('bar')
public readonly defaultGreeting: string;
public constructor(
@Example('baz')
defaultGreeting: string,
) {
this.defaultGreeting = defaultGreeting;
}
@Example('qux')
public greet(
@Example('quux')
greeting: string = this.defaultGreeting,
): string {
return `Hello, ${greeting}`;
}
}
Metadata for classes and class members is provided by the reflect-metadata
package.
const classMetadata: Metadata = MetadataReflector.reflect(Greeter);
expect(classMetadata.getOwn('design:paramtypes')).toStrictEqual([String]);
expect(classMetadata.getOwn(EXAMPLE)).toBe('foo');
const fieldMetadata: Metadata = MetadataReflector.reflect(Greeter.prototype, 'defaultGreeting');
expect(fieldMetadata.getOwn('design:type')).toBe(String);
expect(fieldMetadata.getOwn(EXAMPLE)).toBe('bar');
const methodMetadata: Metadata = MetadataReflector.reflect(Greeter.prototype, 'greet');
expect(methodMetadata.getOwn('design:type')).toBe(Function);
expect(methodMetadata.getOwn('design:paramtypes')).toStrictEqual([String]);
expect(methodMetadata.getOwn('design:returntype')).toBe(String);
expect(methodMetadata.getOwn(EXAMPLE)).toBe('qux');
Metadata for parameters is provided by the Map
object.
If the class or method has design:paramtypes
metadata, the design:type
metadata is set on the parameter.
const constructorParameterMetadata: Metadata = MetadataReflector.reflect(Greeter, null, 0);
expect(constructorParameterMetadata.getOwn('design:type')).toBe(String);
expect(constructorParameterMetadata.getOwn(EXAMPLE)).toBe('baz');
const methodParameterMetadata: Metadata = MetadataReflector.reflect(Greeter.prototype, 'greet', 0);
expect(methodParameterMetadata.getOwn('design:type')).toBe(String);
expect(methodParameterMetadata.getOwn(EXAMPLE)).toBe('quux');
Distributed under the MIT License. See the LICENSE file for more details.