Metadata
Overview
The GetMetadata function provides a reflection-based metadata system built on top of the reflect-metadata library. It retrieves or creates metadata instances associated with target objects, supporting inheritance through the prototype chain.
Store a value on a target
Give your metadata class a unique symbol, then retrieve its instance for the target. Subsequent calls for that target return the same object; no separate save step is needed.
import { GetMetadata } from "@antelopejs/interface-core";
class LabelMetadata {
static key = Symbol("LabelMetadata");
label = "";
constructor(_target: object) {}
}
class UserController {}
const metadata = GetMetadata(UserController.prototype, LabelMetadata);
metadata.label = "users";
const same = GetMetadata(UserController.prototype, LabelMetadata);
// same === metadata; same.label === "users"
Use the constructor or its prototype consistently: they are different targets. The inheritance example shows how to copy a parent's collection without sharing mutable state.
Import
import { GetMetadata } from "@antelopejs/interface-core";
GetMetadata
function GetMetadata<T, U>(
target: U,
meta: Class<T, [U]> & { key: symbol },
inherit?: boolean,
): T;
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
target | U | - | The object to retrieve or create metadata for |
meta | Class<T, [U]> & { key: symbol } | - | A metadata class with a static key symbol |
inherit | boolean | true | Whether to inherit metadata from the prototype chain |
Return value
Returns the metadata instance of type T associated with the target.
Define a metadata class
A metadata class must have a static key property (a Symbol) and accept the target object as a constructor argument.
class RouteMetadata {
static key = Symbol("RouteMetadata");
public routes: Map<string, string> = new Map();
constructor(_target: any) {
// Initialize metadata for the target
}
}
Retrieve metadata
import { GetMetadata } from "@antelopejs/interface-core";
class UserController {
getUser() {}
listUsers() {}
}
const meta = GetMetadata(UserController.prototype, RouteMetadata);
meta.routes.set("getUser", "/users/:id");
meta.routes.set("listUsers", "/users");
Calling GetMetadata multiple times with the same target and metadata class returns the same instance. The metadata is stored on the target using Reflect.defineMetadata.
Inheritance
When first creating metadata and inherit is true (the default), GetMetadata recursively gets or creates metadata on the prototype chain. If the metadata class defines an inherit method, that method receives the parent metadata. Otherwise, properties from the parent are copied only where the child has no such key. In particular, an initialized empty child array prevents the default fallback from copying the parent's array.
class ControllerMeta {
static key = Symbol("ControllerMeta");
public middleware: string[] = [];
constructor(_target: any) {}
inherit(parent: ControllerMeta) {
this.middleware = [...parent.middleware];
}
}
class BaseController {}
const baseMeta = GetMetadata(BaseController.prototype, ControllerMeta);
baseMeta.middleware.push("auth");
class AdminController extends BaseController {}
const adminMeta = GetMetadata(AdminController.prototype, ControllerMeta);
// adminMeta.middleware contains ["auth"] (inherited from BaseController)
adminMeta.middleware.push("adminOnly");
// adminMeta.middleware is now ["auth", "adminOnly"]
// baseMeta.middleware remains ["auth"]
Without a custom inherit method, properties are shallow-copied from parent to child using Object.getOwnPropertyNames, but only for keys that do not already exist on the child metadata instance.
Disable inheritance
Pass false as the third argument to prevent prototype chain traversal:
const meta = GetMetadata(target, RouteMetadata, false);
The flag affects creation only. It does not remove inherited values from an instance that was already created, and changing it on a later call does not rebuild the metadata.
Next steps
- Decorators - Combine metadata with decorator factories
- Modules - Module lifecycle events and management