Skip to content

devalade/reflection-class

Repository files navigation

@devalade/reflection

npm version License: MIT GitHub repository

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.

What this is / isn't

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.

Features

  • 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 / setValue for 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

Installation

npm install @devalade/reflection
# or: yarn / pnpm add @devalade/reflection

Optional peer-style polyfill if you already use the Reflect Metadata ecosystem:

npm install reflect-metadata

Quick start

import { 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']

Plugin discovery sketch

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);
  }
}

Metadata sketch

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);

API overview

ReflectionClass<T> accepts a class constructor or an object instance.

Core

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)

Properties & methods (string names)

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

Rich members

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

Metadata

On ReflectionClass: getMetadata, getOwnMetadata, hasMetadata, getMetadataKeys, getOwnMetadataKeys.

Also exported: Metadata, defineMetadata, getMetadata, getOwnMetadata, getMetadataKeys, getOwnMetadataKeys, hasMetadata, DESIGN_TYPE_KEYS, isConstructable.

Migration notes (2.0)

  • isClass / isInstantiable require a constructable function (arrows return false).
  • Class property listings omit Function builtins (length, name, prototype, …).
  • newInstance on a non-instantiable target throws TypeError (no longer returns null).
  • Prefer hasOwnProp over hasOwnProperty.

License

MIT

About

This is a reflection class for JavaScript. It's inspired by the PHP reflection class

Resources

License

Stars

2 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors