Skip to main content

Managing Dependencies

Managing Dependencies

Defining dependencies is an important factor that makes the difference between efficient and poorly organized codebases. In basica we introduce containers to store dependencies and the relations between them without polluting the current scope. The declarative approach, unlike other frameworks, guarantees you that there will be no circular references.

Singleton

Singleton registration creates a service once and stores the instance. Each time the service is requested, the same instance will be provided.

provider.ts
export interface IStrProvider {
getStr: () => string
}

export class StrProvider1 implements IStrProvider {

getStr() {
return "provider 1";
}
}

export class StrProvider2 implements IStrProvider {

getStr() {
return "provider 2";
}
}
consumer.ts
import { IStrProvider } from "./service"

export class ServiceConsumer {
constructor(private readonly provider: IStrProvider, private readonly name: string) {}

sayHello() {
return `hello from ${this.name}, using ${this.provider.getStr()}`;
}
}
index.ts
import { IocContainer } from "@basica/core/ioc"

import { StrProvider1, StrProvider2 } from "./provider"
import { ServiceConsumer } from "./consumer"

const container = new IocContainer()
.addSingleton("provider1", () => new StrProvider1())
.addSingleton("provider2", () => new StrProvider2())
.addSingleton("consumer1", (c) => new ServiceConsumer(c.provider1, "consumer 1"))
.addSingleton("consumer2", (c) => new ServiceConsumer(c.provider2, "consumer 2"))

console.log(container.items.consumer1.sayHello())
console.log(container.items.consumer2.sayHello())
hello from consumer 1, using provider 1
hello from consumer 2, using provider 2

Transient

Transient registration, meaning that a service will be created each time it's requested, is also supported, but should be considered an escape hatch for managing stateful components.

counter.ts
export class Counter {
get count(private count: number) {
return this.count
}

increment() {
this.count++
}
}
service.ts
import { Counter } from "./service"

export class Service {
constructor(private readonly counter: Counter) {}

add(items: number) {
for (let i = 0; i < items; i++) {
// ...
this.counter.increment()
}
}

get total() {
return this.counter.count
}
}
index.ts
import { IocContainer } from "@basica/core/ioc";

import { Counter } from "./counter";
import { Service } from "./service";

const container = new IocContainer()
.addTransient("counter", () => new Counter(0))
.addSingleton("oranges", (c) => new Service(c.counter(), "orange"))
.addSingleton("apples", (c) => new Service(c.counter(), "apple"));

container.items.oranges.add(3);
container.items.apples.add(2);

console.log("Oranges:", container.items.oranges.total);
console.log("Apples:", container.items.apples.total);
Oranges: 3
Apples: 2