npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

inversify-props

v3.0.0

Published

Wrapper to use inversify as property decorator with TypeScript, useful for component libraries like Vue, React or LitElement

Readme

Inversify Props

Dependency injection for TypeScript, without the boilerplate. inversify-props wraps InversifyJS so you can register a class once and inject it as a property (or constructor parameter) with a single @inject() — no manual ids, no fluent binding ceremony. Framework-agnostic: works with Vue, LitElement, vanilla TS, or anything else. Built on inversify 8.

Using React? Try the companion package inversify-hooks, a thin useInject layer on top of this one.

npm version npm downloads GitHub license GitHub last commit GitHub issues

logo


Table of contents

Why

Plain InversifyJS asks you to manage service identifiers and write fluent bindings for every dependency. inversify-props does that for you: it derives ids from class names automatically and lets you inject by property. You probably don't need it if you want the full power of inversify (custom scopes everywhere, factories, multi-injection) — it's intentionally a thin convenience layer for the common "inject my services" case.

Installation

npm install inversify-props

Built on inversify 8, which is pulled in for you — no separate reflect-metadata install needed. Type definitions and both ESM and CommonJS builds ship with the package.

Note: inversify 8 is ESM-first. Bundlers (Vite, webpack, etc.) need nothing special; consuming it via require() from plain CommonJS Node needs Node 20.19+ or 22+.

TypeScript configuration

inversify-props uses legacy decorators, so enable experimentalDecorators and keep useDefineForClassFields off:

{
  "compilerOptions": {
    "target": "es2020",
    "lib": ["es2020", "dom"],
    "moduleResolution": "bundler",
    "experimentalDecorators": true,
    "useDefineForClassFields": false
  }
}

⚠️ If useDefineForClassFields is true, an injected property's class field shadows the injected getter and reads back undefined. It defaults to false when target is below ES2022.

Quick start

import { cid, container, inject } from 'inversify-props';

// 1. Define a class + interface
interface IService1 {
  method1(): string;
}
class Service1 implements IService1 {
  method1() {
    return 'method 1';
  }
}

// 2. Register it (usually in app.container.ts), before anything resolves
container.addSingleton<IService1>(Service1);

// 3. Inject it anywhere
class MyComponent {
  @inject() service1!: IService1;
}

// ...or resolve it directly
const service1 = container.get<IService1>(cid.IService1);

:warning: If you use a minifier/obfuscator, configure it to preserve class and function names — see Troubleshooting.

Registering dependencies

Register on the shared container before resolving. Three lifetimes are available:

container.addSingleton<IService1>(Service1); // one shared instance (most common)
container.addTransient<ILogger>(Logger);     // a new instance on every resolve
container.addRequest<IUnitOfWork>(UnitOfWork); // one instance per request scope

The generic (<IService1>) is just the compile-time type. The runtime id is derived from the class name and cached under both Service1 and IService1, which is why cid.IService1 works.

Injecting dependencies

Inject as a property — the id is inferred from the property name (camelCase, PascalCase and leading _ are all handled):

export class MyOtherService {
  @inject() private service1: IService1;
  @inject() private _service1: IService1;
  @inject() private Service1: IService1;
}

Constructor injection infers the id from the parameter name:

export class MyOtherService {
  constructor(@inject() private exampleService: IExampleService) {}
}

Custom ids

Don't want auto-generated ids? Pass your own:

container.addSingleton<IService1>(Service1, 'MyService1');

export class MyComponent {
  @inject('MyService1') service1!: IService1;
}

Your own container

The library ships a ready-to-use container, but you can create and install your own:

import { Container, setContainer } from 'inversify-props';

setContainer(new Container());

Testing with mocks

The recommended pattern, before each test: reset the container, re-register dependencies, then mock what the test needs.

import { cid, mockSingleton, resetContainer } from 'inversify-props';

beforeEach(() => {
  resetContainer();
  containerBuilder(); // your registrations
  mockSingleton<IHttpService>(cid.IHttpService, HttpServiceMock);
});

mockTransient and mockRequest have the same signature. resetContainer() unbinds everything.

API reference

| Export | Description | | --- | --- | | container | The shared container instance (auto-created). | | container.addSingleton<T>(Class, id?) | Register a single shared instance. | | container.addTransient<T>(Class, id?) | Register a new instance per resolve. | | container.addRequest<T>(Class, id?) | Register one instance per request scope. | | container.get<T>(id) | Resolve a dependency by id. | | cid | Cache of generated ids, e.g. cid.IService1. | | inject / Inject | Property/parameter decorator for injecting dependencies. | | injectable | Class decorator marking a class as injectable. | | mockSingleton / mockTransient / mockRequest | Replace a registered id with another implementation (testing). | | resetContainer() | Unbind everything from the container. | | getContainer() / setContainer(opts) | Access or replace the underlying InversifyJS container. | | Container | The container class, if you want your own instance. |

Use it as an agent skill

This repo ships an Agent Skill so AI coding agents (Claude Code, Cursor, etc.) know how to wire up DI with this library. Install it with npx skills:

npx skills add CKGrafico/inversify-props

Troubleshooting

| Symptom | Cause & fix | | --- | --- | | Injected property is undefined | useDefineForClassFields is true. Set it to false (or keep target below ES2022). | | Works in dev, breaks in production | The minifier mangled class names, so cid.IXxx is undefined. Enable keepNames (esbuild/Vite) or keep_classnames + keep_fnames (Terser/Uglify). Vue CLI uses Terser under the hood — set it via configureWebpackoptimization.minimizer. | | No matching bindings found | The service wasn't registered, or registration ran after it was resolved. Register first. | | Decorators throw at runtime | experimentalDecorators is off in your tsconfig.json. |

Credits

Built on InversifyJS. Licensed under MIT.