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

inzect

v1.5.0

Published

Inzect is a lightweight injection container for TypeScript and JavaScript.

Readme

Inzect

npm npm

Inzect is a lightweight injection container for TypeScript and JavaScript.
It is built upon Stage 3 Decorators Proposal.

📑 Table of contents

⚙️ Installation

Install by npm

npm install --save inzect

or install with yarn

yarn add inzect

or install with pnpm

pnpm add inzect

Inzect is built upon the Stage 3 Decorators Proposal.
Please ensure that your tsconfig.json is configured to support Stage 3 decorators.
Specifically, do not enable experimentalDecorators or emitDecoratorMetadata, or simply omit them from the configuration:

// tsconfig.json

{
  "compilerOptions": {
    // ...
    "experimentalDecorators": false,
    "emitDecoratorMetadata": false
  }
}

📘 APIs

Inzect performs Constructor Injection on the constructors of decorated classes.

Decorators

@Injectable()

Marks a class as available for dependency injection. Use this decorator to register a class as a provider that can be injected into other classes.

Parameters

  • token — Injection Token (see Token). Leave empty to use the decorated class as the token.
  • scope (default: Lifecycle.Transient) — Lifecycle scope (see Lifecycle Scope).

Usage

// logger-service.ts

import { Injectable } from 'inzect';

@Injectable()
export class Logger {
  public log(message: string): void {
    console.log(`[LOG]: ${message}`);
  }
}
// index.ts

import { container } from 'inzect';
import { Logger } from '~examples/modules/logger';

const logger = container.resolve(Logger);
logger.log('Hello world!');

@Inject()

Specifies a dependency to be injected. Use this decorator to inject into class fields or class properties. Or use this decorator to inject into constructor parameters.

  1. Inject into class fields or class properties.

    Parameters

    • token — Injection Token (see Token).
    • optional (default: false) — Whether the dependency is optional.

    Usage

    // app.ts
    
    import { Inject } from 'inzect';
    import { Logger } from '~examples/modules/logger';
    
    export class App {
      @Inject(Logger)
      readonly #logger!: Logger;
    
      run(): void {
        this.#logger.log('Hello world!');
      }
    }
  2. Inject into constructor parameters.

    Parameters

    • injects — List of Inject Parameter. Inject parameters are used to inject dependencies into the constructor.

    Usage

    // app.ts
    
    import { Inject } from 'inzect';
    import { Logger } from '~examples/modules/logger';
    
    @Inject([Logger])
    export class App {
      readonly #logger: Logger;
    
      public constructor(logger: Logger) {
        this.#logger = logger;
      }
    
      run(): void {
        this.#logger.log('Hello world!');
      }
    }

@Scope()

Defines the lifecycle scope of a provider. Use this decorator to control how and when instances are created.

Parameters

  • scope (default: Lifecycle.Transient) — Lifecycle scope (see Lifecycle Scope).

Usage

// database.ts

import { Lifecycle, Scope } from 'inzect';

@Scope(Lifecycle.Singleton)
export class Database {
  public async connect(): Promise<void> {
    console.log('Database connected');
  }
}

Container

The Container is the core of the Inzect dependency injection system. It manages provider registration, resolution, and instance lifecycle.
The general principle behind Inversion of Control (IoC) containers is: you give the container a token, and in exchange you get an instance or value.

Inzect adheres to the Stage 3 Decorators specification of ECMAScript. Unlike legacy decorators, Stage 3 does not support emitDecoratorMetadata, which means the container cannot infer types from TypeScript metadata.

Therefore, you must explicitly specify the token to inject in most cases, using the @Inject() to decorate (see Inject).

container.register()

Registers a provider with the container.

Parameters

  • options.token — Injection Token (see Token).
  • options.provider — Injection Provider (see Provider).
  • options.scope (default: Lifecycle.Transient) — Lifecycle scope (see Lifecycle Scope).

Usage

// index.ts

import { container, Lifecycle } from 'inzect';
import { Logger } from '~examples/modules/logger';

container.register({
  token: 'logger',
  provider: {
    useClass: Logger,
  },
  scope: Lifecycle.Resolution,
});

container.unregister()

Unregister a dependency.

Parameters

  • token — Injection Token (see Token).

Usage

// index.ts

import { container } from 'inzect';

class Service {}

container.register({
  token: Service,
  provider: {
    useClass: Service,
  },
});

console.log(container.isRegistered(Service)); // true

container.unregister(Service);
console.log(container.isRegistered(Service)); // false

container.isRegistered()

Check if a dependency is registered.
It only checks the current container, not the parent containers.

Parameters

  • token — Injection Token (see Token).

Usage

// index.ts

import { container, Injectable } from 'inzect';

@Injectable()
class Service {}

console.log(container.isRegistered(Service)); // true
console.log(container.isRegistered('some-token')); // false

container.clear()

Clears all registered dependencies. It only clears the current container, not the parent containers.

Usage

// index.ts

import { container } from 'inzect';

class Service {}

container.register({
  token: Service,
  provider: {
    useClass: Service,
  },
});

console.log(container.isRegistered(Service)); // true

container.clear();
console.log(container.isRegistered(Service)); // false

container.resolve()

Resolves a dependency.

Parameters

  • token — Injection Token (see Token).
  • optional (default: false) — Whether the dependency is optional.

Usage

// index.ts

import { container } from 'inzect';
import { Logger } from '~examples/modules/logger';

const LOGGER_TOKEN = Symbol('logger');

container.register({
  token: LOGGER_TOKEN,
  provider: {
    useClass: Logger,
  },
});

const logger = container.resolve<Logger>(LOGGER_TOKEN);
logger.log('Hello world!');

container.resolveAsync()

Resolves a class or token asynchronously. This method is required when any of the class's dependencies (constructor parameters) are registered using asynchronous factory providers. Unlike resolve(), which works only with synchronous resolution chains, resolveAsync() ensures proper handling of nested or recursive dependencies that rely on asynchronous instantiation.

Parameters

  • token — Injection Token (see Token).
  • optional (default: false) — Whether the dependency is optional.

Usage

// index.ts

import { container } from 'inzect';

const TIMESTAMP_TOKEN = Symbol('data');

// Fake async data
function fetchTimestamp(): Promise<number> {
  return new Promise<number>((resolve) => {
    setTimeout(() => {
      resolve(Date.now());
    }, 1000);
  });
}

container.register({
  token: TIMESTAMP_TOKEN,
  provider: {
    useFactory: fetchTimestamp,
  },
});

const data = await container.resolveAsync(TIMESTAMP_TOKEN);
console.log(data); // Current timestamp

container.createChild()

Creates a child container that shares access to the registrations of its parent.
When resolving a dependency in the child container, if the token is not registered locally, the lookup will fall back to the parent container.

Usage

// index.ts

import { container, Lifecycle } from 'inzect';

class Service {}

const childContainer1 = container.createChild();
childContainer1.register({
  token: 'Service',
  provider: {
    useClass: Service,
  },
  scope: Lifecycle.Singleton,
});

const childContainer2 = container.createChild();
childContainer2.register({
  token: 'Service',
  provider: {
    useClass: Service,
  },
  scope: Lifecycle.Singleton,
});

const service1 = childContainer1.resolve('Service');
const service2 = childContainer2.resolve('Service');

console.log(service1 === service2); // false

Sharing access to the registrations of its parent

// index.ts

import { container, Lifecycle } from 'inzect';

class Service {}

container.register({
  token: 'Service',
  provider: {
    useClass: Service,
  },
  scope: Lifecycle.Singleton,
});

const childContainer1 = container.createChild();
const childContainer2 = container.createChild();

const service1 = childContainer1.resolve('Service');
const service2 = childContainer2.resolve('Service');

console.log(service1 === service2); // true

Injection

Token

An injection token is used to identify a provider.

Such tokens can be:

  • Class: class, abstract class
  • Primitive: string, number, boolean, symbol, bigint

Provider

Class Injection Provider

A class injection provider is used to provide an instance of a class.

Properties

  • useClass — Class to provide.

Usage

// index.ts

import { container } from 'inzect';
import { Logger } from '~examples/modules/logger';

container.register({
  token: 'logger',
  provider: {
    useClass: Logger,
  },
});
Value Injection Provider

A value injection provider is used to provide a value.

Properties

  • useValue — Value to provide.

Usage

// index.ts

import { container } from 'inzect';

container.register({
  token: 'isProduction',
  provider: {
    useValue: process.env['NODE_ENV'] === 'production',
  },
});
Factory Injection Provider

A factory injection provider is used to provide an instance using a factory function.

Properties

  • useFactory — Factory function.
  • inject — List of Inject Parameter. Inject parameters are used to inject dependencies into the factory function.

Usage

// index.ts

import { container } from 'inzect';
import { Logger } from '~examples/modules/logger';

container.register({
  token: 'database-connection',
  provider: {
    inject: [
      Logger,
      {
        token: 'isProduction',
        optional: true,
      },
    ],
    useFactory: (logger: Logger, isProduction?: boolean) => {
      if (isProduction) {
        return 'production-connection';
      }

      logger.log('Using development connection');
      return 'development-connection';
    },
  },
});

Lifecycle Scope

The lifecycle scope of a provider defines how and when instances are created and reused.

Values

  • Lifecycle.Singleton — One shared instance across the entire application.
  • Lifecycle.Transient — A new instance is created every time the provider is injected.
  • Lifecycle.Resolution — A new instance is created per resolution graph (i.e. per container.resolve() call), and reused within that resolution graph.
  • Lifecycle.Container — A new instance is created per container (i.e. per container.createChild() call), and reused within that container itself.

Usage

  1. Singleton Scope

    // index.ts
    
    import { container, Lifecycle, Scope } from 'inzect';
    
    @Scope(Lifecycle.Singleton)
    class Service {}
    
    const service1 = container.resolve(Service);
    const service2 = container.resolve(Service);
    
    console.log(service1 === service2); // true
  2. Transient Scope

    // index.ts
    
    import { container, Lifecycle, Scope } from 'inzect';
    
    @Scope(Lifecycle.Transient)
    class Service {}
    
    const service1 = container.resolve(Service);
    const service2 = container.resolve(Service);
    
    console.log(service1 === service2); // false
  3. Resolution Scope

    // index.ts
    
    import { container, Inject, Lifecycle, Scope } from 'inzect';
    
    @Scope(Lifecycle.Resolution)
    class Service {}
    
    @Inject([Service])
    class App {
      @Inject(Service)
      readonly #service1!: Service;
      readonly #service2: Service;
    
      public constructor(service2: Service) {
        this.#service2 = service2;
      }
    
      run(): void {
        console.log(this.#service1 === this.#service2); // true
      }
    }
    
    const app = container.resolve(App);
    app.run();
  4. Container Scope

    // index.ts
    
    import { container, Lifecycle } from 'inzect';
    
    class Service {}
    
    container.register({
      token: 'Service',
      provider: {
        useClass: Service,
      },
      scope: Lifecycle.Container,
    });
    
    const childContainer = container.createChild();
    
    try {
      childContainer.resolve('Service');
    } catch (error) {
      // It will throw an error because the scope is Container, childContainer can't resolve Service that is registered in global container
    }

🧪 Planned Features

The following features are not yet implemented in Inzect but are planned for future releases:

Circular Dependencies

Support for automatically resolving circular dependencies using lazy proxies or factory wrappers. This requires careful lifecycle management and reference deferral.

Disposable Instances

Support for [Symbol.dispose] and [Symbol.asyncDispose] to allow cleanup logic for services (e.g., closing DB connections, unsubscribing from streams).

Interception

This enables you to hook into the container's internal resolution flow to perform tasks like:

  • Logging tokens being resolved
  • Measuring resolution time
  • Auditing resolved instances

It provides two main hooks:

  • beforeResolution – called before the container resolves a dependency
  • afterResolution – called after the instance is resolved

This is useful for logging, metrics, and debugging.

📄 License

This project is licensed under the MIT License.

You are free to use, modify, and distribute this library in both commercial and non-commercial projects.


🤝 Contributing

Inzect is an open-source project, and contributions are welcome!

Whether it's a bug report, feature request, documentation improvement, or pull request — your input helps make the library better for everyone.

To get started:

  1. Fork the repository
  2. Create a feature branch
  3. Submit a pull request

For major changes or architectural discussions, please open an issue first to discuss your ideas.

Together we can build a more powerful dependency injection system for TypeScript.