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

@lytical/ioc

v1.0.5

Published

TypeScript Inversion of Control (IoC, Dependency Injection) for Node

Readme

@lytical/ioc

typescript inversion of control (ioc, dependency injection) for node

a lightweight, self contained, inversion of control (ioc), node, typescript library for managing dependency injection in your applications.

features

  • no dependencies
  • lightweight
  • inject dependencies into constructors and or invoke class method arguments using @decorators
  • auto register injectable classes using @decorators
  • supports singleton; option; and factory patterns

getting started

after installing ioc, configure your tsconfig.json file to enable decorators.

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

usage

decorate your injectables using @ioc_injectable(), and then use the container to create an instance of the injectable.

most common use case

import { ioc_injectable } from '@lytical/ioc';
import collection from '@lytical/ioc/collection';

@ioc_injectable()
export class test_svc {
  do_something(): string {
    return 'done';
  }
}

// a container is "locked" once created,
// so make sure all injectables are registered first
collection.create_container().then((sc) => {
  const ts = sc.get(test_svc);
  console.debug(ts?.do_something()); // 'done'
  console.debug({ is_same_instance: ts === sc.get(test_svc) });
  // { is_same_instance: false }
});

module-local class...

import { ioc_injectable } from '@lytical/ioc';
import collection from '@lytical/ioc/collection';

// note: this class is not exported
class my_local_svc {
  do_something(): string {
    return 'done';
  }
}

@ioc_injectable(my_local_svc)
export abstract class test_svc {
  abstract do_something(): string;
}

collection.create_container().then((sc) => {
  const ts = sc.get(test_svc);
  console.debug(ts?.do_something()); // 'done'
});

factory...

import { ioc_injectable } from '@lytical/ioc';
import collection from '@lytical/ioc/collection';

// note: the next 2 classes are not exported
class dev_version_svc {
  do_something(): string {
    return 'done in dev';
  }
}

class prod_version_svc {
  do_something(): string {
    return 'done in prod';
  }
}

const is_dev_environment = process.env['NODE_ENV'] === 'development';

@ioc_injectable(() =>
  is_dev_environment ? new dev_version_svc() : new prod_version_svc(),
)
export abstract class test_svc {
  abstract do_something(): string;
}

collection.create_container().then((sc) => {
  const ts = sc.get(test_svc);
  console.debug(ts?.do_something()); // 'done in [dev|prod]'
});

singleton...

import { ioc_injectable } from '@lytical/ioc';
import collection from '@lytical/ioc/collection';

@ioc_injectable(() => [[new test_svc()]])
// note: the return [[instance]]...
export class test_svc {
  do_something(): string {
    return 'done';
  }
}

collection.create_container().then((sc) => {
  const ts = sc.get(test_svc);
  console.debug(ts?.do_something()); // 'done'
  console.debug({ is_same_instance: ts === sc.get(test_svc) });
  // { is_same_instance: true }
});

create instances with dependencies in the constructors...

import { ioc_create_instance, ioc_inject, ioc_injectable } from '@lytical/ioc';
import collection from '@lytical/ioc/collection';

@ioc_injectable()
export class test_svc {
  do_something(): string {
    return 'done';
  }
}

class use_svc {
  // constructor with dependencies
  constructor(@ioc_inject(test_svc) public readonly svc: test_svc) {}
}

collection.create_container().then(() => {
  // ioc_create_instance() can instantiate any class and inject dependencies if needed...
  const cls = ioc_create_instance(use_svc);
  console.debug(cls.svc?.do_something()); // 'done'
});

invoke class methods (instance and static) with dependencies...

import { ioc_create_instance, ioc_inject, ioc_injectable } from '@lytical/ioc';
import collection from '@lytical/ioc/collection';

@ioc_injectable()
export class test_svc {
  do_something(): string {
    return 'done';
  }
}

class use_svc {
  do_it(@ioc_inject(test_svc) svc?: test_svc, suffix?: string) {
    return (svc?.do_something() ?? '') + suffix;
  }

  static do_it_static(@ioc_inject(test_svc) svc?: test_svc, suffix?: string) {
    return (svc?.do_something() ?? '') + suffix;
  }
}

collection.create_container().then(() => {
  const cls = new use_svc();

  // invoke instance method
  let rs = ioc_invoke_method(cls.do_it, cls, ' again');
  console.log(rs); // 'done again'

  // invoke static method
  rs = ioc_invoke_method(use_svc.do_it_static, use_svc, ' static');
  console.log(rs); // 'done static'
});

configure and inject 'option' dependencies

import { ioc_inject, ioc_injectable } from '@lytical/ioc';
import collection from '@lytical/ioc/collection';

class test_opts {
  a?: number;
  b?: string;
  c?: boolean;
}

@ioc_injectable()
export class test_svc {
  constructor(@ioc_inject(test_opts) public readonly option: test_opts) {}

  do_something(): string {
    return `a=${this.option.a}, b=${this.option.b}, c=${this.option.c}`;
  }
}

// configure_option() can be called multiple times for the same type
collection.configure_option(test_opts, { a: 42 });
collection.configure_option(test_opts, { b: 'hello' });
collection.configure_option(test_opts, () => ({ c: true }));

// overrides previous 'a' and 'c' asynchronously, great for i/o operations
collection.configure_option(test_opts, () =>
  Promise.resolve({ a: 10, c: false }),
);

collection.create_container().then((sc) => {
  const ts = sc.get(test_svc);
  console.debug(ts?.do_something()); // a=10, b=hello, c=false

  // options are immutable
  try {
    ts!.option.a = 100;
  } catch (e) {
    console.debug(e);
    // TypeError: Cannot assign to read only property 'a' of...
  }
});

see @lytical/ioc at work

@lytical/app is a library for quickly building express server applications.
check it out at https://www.npmjs.com/package/@lytical/app
see an example project at https://github.com/lytical/ts-app-example

documentation

* ioc_collection_t

represents an inversion of control collection which is the default returned from '@lytical/ioc/collection'

import collection from '@lytical/ioc/collection'

utilize it to configure services; options and to initialize the container. loaded node modules containing injectables will register services into the collection automatically. all registrations; node modules and their dependencies, containing injectables, should be loaded before creating the container. manually register services, and import modules containing injectables to ensure they are registered.

| method | description | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | configure_option | configure an option for a type | | create_container | initialize and get the ioc container. call this method after all services are registered. this can be called just before listening for requests in a server application, or in a start hook in an azure function application | | has | check if a type is registered in the collection | | set | register a service factory for a type | | set_func | register a service function. the container will return the function instead of invoking it |

* ioc_container_t

represents an inversion of control container which is the default returned from '@lytical/ioc'

import container from '@lytical/ioc'

utilize to retrieve service and 'option' instances.

| method | description | | ------------- | -------------------------------------------------------------------------------------------------- | | get | get a service from the container | | get_or_create | get a service from the container or create an instance of the provided type | | has | check if a service is registered in the container | | require | get the required specified services. an assert exception is throw if the service is not registered |

* @ioc_injectable(arg?)

decorates a class as an injectable service

@ioc_injectable()
export class test_svc {}

a delegate function can be specified as an argument (delegate(svc: container): unknown|[[unknown]]) to implement a factory pattern.
this delegate will be invoked when the service instance is requested.
if a delegate function returns an array, within an array, containing a single element ([[unknown]]),
this element will replace the delegate as the service instance or type.
this allows for lazy evaluation of the service instance or type, and is the only case where the container is mutated.

* @ioc_inject(type)

decorates a class method argument, indicating the type of service to inject.

class my_class {
  constructor(@ioc_inject(logger_svc) private readonly _log?: logger_svc) {}

  my_method(@ioc_inject(test_svc) svc: test_svc) {}
}

* ioc_create_instance(type, ...args)

create an instance of the specified class, by injecting dependencies obtained from the ioc container.
optional arguments may be provided to append to the constructor arguments.

const svc = ioc_create_instance(my_class);

* ioc_get_method_args(type_or_instance, method_name)

returns the an array of method arguments, by obtaining dependencies obtained from the ioc container.

const svc = ioc_get_method_args(my_class, 'do_something');

* ioc_invoke_method(method, type_or_instance, ...args)

invoke the specified class method, by injecting dependencies obtained from the ioc container.
optional arguments may be provided to append to the method arguments.

const cls = new my_class();
const result = ioc_invoke_method(cls.do_something, cls);

Stay tuned! I have more packages to come.`

lytical(r) is a registered trademark of lytical, inc. all rights are reserved.