Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

cheap-di

Package Overview
Dependencies
Maintainers
1
Versions
71
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cheap-di

TypeScript dependency injection like Autofac in .Net

  • 4.0.0-rc.2
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
76
increased by1420%
Maintainers
1
Weekly downloads
 
Created
Source

cheap-di

JavaScript's dependency injection like Autofac in .Net

  • How to use
  • Registration variants

How to use

The recommended way of using this package is using it with code transformers like cheap-di-ts-transform. Because in this way you will get the truly dependency injection:

abstract class Logger {
  abstract debug: (message: string) => void;
}

class ConsoleLogger implements Logger {
  constructor(public prefix: string) {}

  debug(message: string) {
    console.log(`${this.prefix}: ${message}`);
  }
}

class Service {
  constructor(private logger: Logger) {}

  doSome() {
    this.logger.debug('Hello world!');
  }
}
/**
 * With cheap-di-ts-transform here will be added information about Service dependencies.
 * It will looks like:
 * @example
 * import { findOrCreateMetadata } from 'cheap-di';
 * 
 * // for Logger
 * try {
 *   const metadata = findOrCreateMetadata(Logger);
 *
 *   // only classes may be instantiated with DI, other parameters can be filled with argument injection
 *   metadata.dependencies = ["unknown"];
 * } catch {}
 *
 * // for Service
 * try {
 *   const metadata = findOrCreateMetadata(Service);
 *
 *   metadata.dependencies = [Logger];
 * } catch {}
 * */ 

// somewhere in you application initialization
import { container } from 'cheap-di';

const myLogPrefix = 'INFO: ';
container.registerType(ConsoleLogger).as(Logger).with(myLogPrefix);

// somewhere in inside your code
// or you may use some middleware to do this, to get rid of Service Locator antipattern
import { container } from 'cheap-di';

const service = container.resolve(Service);
service.doSome();

But if you can't use transformers you still may use cheap-di with decorators:

import { inject } from 'cheap-di';

abstract class SessionAccessor {
  abstract getSession(): string;
}

abstract class Logger {
  abstract debug(message: string): void;
}
abstract class InfoLogger extends Logger {}
abstract class ErrorLogger extends Logger {}

// non-classes-arguments specified as "unknown"
@inject('unknown', SessionAccessor)
class ConsoleLogger implements Logger {
  constructor(public prefix: string, private sessionAccessor: SessionAccessor) {}

  debug(message: string) {
    console.log(`[${this.sessionAccessor.getSession()}] ${this.prefix}: ${message}`);
  }
}

class Service {
  constructor(private logger: InfoLogger) {}

  doSome() {
    this.logger.debug('Hello world!');
  }
}

// somewhere
import { container } from 'cheap-di';

const infoPrefix = 'INFO: ';
container.registerType(ConsoleLogger).as(InfoLogger).with(infoPrefix);

const errorPrefix = 'ERROR: ';
container.registerType(ConsoleLogger).as(ErrorLogger).with(errorPrefix);

// somewhere in inside your code
// or you may use some middleware to do this, to get rid of Service Locator antipattern
import { container } from 'cheap-di';

const service = container.resolve(Service);
service.doSome();

Registration variants

registerImplementation

If you would like to specify implementation of your interface:

import { container } from 'cheap-di';

abstract class Service {/**/}
class ServiceImpl extends Service {/**/}

container
  .registerImplementation(ServiceImpl)
  .as(Service);

Or if you want to inject some parameters to its constructor:

import { container } from 'cheap-di';

class Some {
  constructor(private name: string) {}
}

container
  .registerImplementation(Service)
  .inject('some name');

Or if you want to have only one instance of the implementation class:

import { container } from 'cheap-di';

class Some {}

container
  .registerImplementation(Service)
  .asSingleton();

And singleton also may be used with interface specification:

import { container } from 'cheap-di';

abstract class Service {/**/}
class ServiceImpl extends Service {/**/}

container
  .registerImplementation(ServiceImpl)
  .asSingleton(Service);

And even with argument injection:

import { container } from 'cheap-di';

abstract class Service {/**/}

class ServiceImpl extends Service {
  constructor(private name: string) {
    super();
  }
}

container
  .registerImplementation(ServiceImpl)
  .asSingleton(Service)
  .inject('some name');
registerInstance

If you want to register some instance as interface

import { container } from 'cheap-di';

abstract class Database {
  abstract get(): Promise<string>;
}

const db: Database = {
  async get() {
    return Promise.resolve('name1');
  },
};

container.registerInstance(db).as(Database);

You can see more examples in cheap-di/src/ContainerImpl.test.ts

Changelog

Keywords

FAQs

Package last updated on 15 Nov 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc