Ergonomic runtime introspection for JavaScript classes and objects. Discover names, inheritance, properties, methods (with descriptors), invoke members dynamically, and optionally read decorator metadata — without pulling in a framework.
Is: a small, zero-dependency helper over prototype walks, property descriptors, and new — aimed at plugin systems, serializers, validators, and lightweight DI.
Isn't: PHP/Java reflection. JavaScript has no runtime parameter lists, true visibility, or attributes unless you add metadata (decorators / emitDecoratorMetadata). TypeScript private is erased at compile time; #private fields are not listed as normal properties.
- Class and instance introspection (name, constructor, prototype, parent)
- Property and method discovery (own + inherited); Function builtins filtered on classes
- Rich members: kind (
data|accessor|method), descriptors, symbol keys invoke/getValue/setValuefor dynamic tooling- Instantiation with honest
isInstantiable()(arrows / bound fns are not constructors) - Opt-in decorator metadata (built-in store, or interoperates with
reflect-metadata) - TypeScript-first, ESM-only
npm install @devalade/reflection
# or: yarn / pnpm add @devalade/reflectionOptional peer-style polyfill if you already use the Reflect Metadata ecosystem:
npm install reflect-metadataimport { ReflectionClass } from '@devalade/reflection';
class Greeter {
constructor(public greeting: string) {}
greet() {
return this.greeting;
}
static create(greeting: string) {
return new Greeter(greeting);
}
}
const reflect = new ReflectionClass(Greeter);
reflect.getName(); // 'Greeter'
reflect.isClass(); // true
reflect.getOwnMethods(); // ['create']
reflect.getMethod('greet'); // { kind: 'method', static: false, descriptor, ... }
const instance = reflect.newInstance('Hello');
new ReflectionClass(instance).getOwnProperties(); // ['greeting']import { ReflectionClass } from '@devalade/reflection';
type Plugin = { name: string; new (): { run(): void } };
function registerPlugins(ctors: Plugin[]) {
for (const Ctor of ctors) {
const r = new ReflectionClass(Ctor);
if (!r.isInstantiable() || !r.getMethod('run')) continue;
const plugin = r.newInstance();
r.invoke('run', plugin);
}
}import { Metadata, ReflectionClass, defineMetadata } from '@devalade/reflection';
@Metadata('role', 'admin')
class UserService {
@Metadata('inject', 'db')
save() {}
}
const r = new ReflectionClass(UserService);
r.getMetadata('role'); // 'admin'
r.getMetadata('inject', 'save'); // 'db'
// Or without decorators:
defineMetadata('version', 1, UserService);ReflectionClass<T> accepts a class constructor or an object instance.
| Method | Description |
|---|---|
getName() |
Constructor name |
getConstructor() |
Constructor function |
getPrototype() |
Prototype object |
getParentClass() / getParentClassName() |
Inheritance |
isClass() / isInstance() |
Constructable class vs object |
isInstantiable() |
Can safely use new / newInstance |
newInstance(...args) |
Construct; throws if not instantiable |
isInstanceCheck(obj) |
instanceof (class targets only) |
| Method | Description |
|---|---|
getOwnProperties() / getProperties() |
Property names (builtins filtered on classes) |
getOwnMethods() / getMethods({ sort? }) |
Method names; sorting is enabled by default and can be disabled for a lower-cost enumeration |
hasOwnProp(name) |
Own property check (preferred) |
hasOwnProperty(name) |
Deprecated alias of hasOwnProp |
hasProperty / hasOwnMethod / hasMethod |
Presence checks |
| Method | Description |
|---|---|
getMembers({ includeSymbols? }) |
All members with descriptors |
getProperty(name) |
Data/accessor member or null |
getMethod(name) |
Method member or null |
invoke(name, thisArg?, ...args) |
Call a method |
getValue / setValue |
Read/write on an instance |
On ReflectionClass: getMetadata, getOwnMetadata, hasMetadata, getMetadataKeys, getOwnMetadataKeys.
Also exported: Metadata, defineMetadata, getMetadata, getOwnMetadata, getMetadataKeys, getOwnMetadataKeys, hasMetadata, DESIGN_TYPE_KEYS, isConstructable.
isClass/isInstantiablerequire a constructable function (arrows returnfalse).- Class property listings omit Function builtins (
length,name,prototype, …). newInstanceon a non-instantiable target throwsTypeError(no longer returnsnull).- Prefer
hasOwnPropoverhasOwnProperty.
MIT