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

@drewjbartlett/tiny-ioc

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@drewjbartlett/tiny-ioc

`tiny-ioc` is a lightweight (less than 1kB) dependency injection / IOC container for TypeScript.

  • 0.0.16
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
1
decreased by-80%
Maintainers
1
Weekly downloads
 
Created
Source

Tiny IOC

tiny-ioc is a lightweight (less than 1kB) dependency injection / IOC container for TypeScript.

Core CI

Features

  • ✅ 100% TypeScript
  • ✅ lightweight - < 1kB
  • ✅ bind & unbind dependencies
  • ✅ bind singletons and reset if necessary
  • ✅ bind factories
  • ✅ support for swapping dependencies
  • ✅ simplfies testing / mocking

Installation

npm i @drewjbartlett/tiny-ioc --save

Usage

Create a container.ts file that creates, binds, and then exports the container.

// container.ts
import { createContainer, Scope } from '@drewjbartlett/tiny-ioc';

const container = createContainer();

container.bind(MyClass, () => new MyClass(), Scope.Singleton);
container.bindFactory(DataSource, () => new DataSource(container.get(HttpClient)));
container.bindSingleton(HttpClient, () => new HttpClient());

export { container }
// some-other-file.ts

import { container } from 'path/to/container';
import { DataSource } from 'path/to/data-source';

export async function makeRequest() {
  try {
    const dataSource = container.get(DataSource);

    return await dataSource.get('/foo/bar');
  } catch (e) {
    //
  }
}

API

bind<T>(binding: Binding<T>, value: FactoryFunction<T>, scope: Scope): void

Bind a dependency with a given scope.

import { createContainer, Scope } from '@drewjbartlett/tiny-ioc';

const container = createContainer();

container.bind(SomeClass, () => new SomeClass(container.get(AnotherClass)), Scope.Singleton);
container.bind(AnotherClass, () => new AnotherClass(), Scope.Factory);

bindSingleton<T>(binding: Binding<T>, factory: FactoryFunction<T>): void

Bind a dependency to the container as a singleton.

class Total {
  constructor(public readonly count: number) {}
}

let count = 0;

container.bindSingleton(
  Total,
  () => {
    count++;

    return new Total(count);
  },
);

container.get(Total).count; // 1
container.get(Total).count; // 1
container.get(Total).count; // 1
container.get(Total).count; // 1

bindFactory<T>(binding: Binding<T>, factory: FactoryFunction<T>): void

Bind a dependency to the container as a factory. Each time the dependency is resolved the container will call the factory function.

class Total {
  constructor(public readonly count: number) {}
}

let count = 0;

container.bindFactory(
  Total,
  () => {
    count++;

    return new Total(count);
  },
);

container.get(Total).count; // 1
container.get(Total).count; // 2
container.get(Total).count; // 3
container.get(Total).count; // 4
bindOnce<T>(binding: Binding<T>, value: FactoryFunction<T>, scope: Scope): void

Only bind the given value if there is not already a binding.

container.bindFactory(HttpClient, () => new HttpClient({ baseURL: 'baseURL 1' }));
container.bindOnce(HttpClient, () => new HttpClient({ baseURL: 'baseURL 2' }), Scope.Singleton);

container.get(HttpClient).baseURL // 'baseURL 1'
get<T>(binding: Binding<T>): T

Attempt to resolve a given binding. Will throw a NotBoundException if there is no binding found.

container.get(SomeDependency);
resetSingleton<T>(binding: Binding<T>): void

Reset a singleton value.

If a value has been previously resolved and is bound as a singleton, this will keep the binding but reset the singleton value until the next resolve. Take the example below. Each time the singleton dependency is built the count will increase. Since it's a singleton count will always be 1. After resetting the singleton the new value is 2 since the factory function is called again.

let count = 0;

container.bindSingleton(
  Total,
  () => {
    count++;

    return new Total(count);
  },
);

container.get(Total).count // 1
container.get(Total).count // 1

container.resetSingleton(Total);

container.get(Total).count // 2
bound<T>(binding: Binding<T>): boolean

Determine if a binding exists or not.

container.bound(HttpClient); // false

container.bindFactory(HttpClient, () => new HttpClient());

container.bound(HttpClient); // true
unbind<T>(binding: Binding<T>): void

Remove the given binding from the container entirely.

container.bindFactory(HttpClient, () => new HttpClient());

container.get(HttpClient); // HttpClient

container.unbind(HttpClient); 

container.get(HttpClient); // throws NotBoundException
swap<T>(oldBinding: Binding<T>, newBinding: FactoryFunction<T>): void

Swap the old binding's value with the new value. This is useful when testing.

There may be times where swapping a dependency is necessary. Especially when testing. swap allows for swapping out a dependency by a given class name.

class Tesla extends Car {

}

class Rivian extends Car {

}

container.bindFactory(Car, () => new Tesla());

container.get(Car); // Tesla

container.swap(Car, () => new Rivian());

container.get(Car); // Rivian

Using in tests

Unit testing is made very simple when using tiny-ioc. You can simply swap out the real dependency for any mock dependency and the tests will reference your mock instead of the real thing.

// make-request.ts

import { container } from 'path/to/container';
import { HttpClient } from 'path/to/http-client';

export async function makeRequest() {
  try {
    const dataSource = container.get(HttpClient);

    return await dataSource.get('/foo/bar');
  } catch (e) {
    //
  }
}
// make-request.test.ts

import { container } from 'path/to/container';
import { HttpClient } from 'path/to/http-client';
import { makeRequest } from 'path/top/make-request';

class DummyHttpClient {
  get(url: string) {
    return dummyData;
  }
}

it('should make the request', () => {
  container.swap(HttpClient, () => new DummyHttpClient());

  await myRequest(); // calls .get() on DummyHttpClient instead of HttpClient
})

Keywords

FAQs

Package last updated on 06 Mar 2024

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