Skip to main content

Conditional Bindings

Brandi allows you to use tags and targets to control which implementation of the abstraction will be injected to a target.

Creating tokens:

tokens.ts
import { token } from 'brandi';
import type { Cacher } from './Cacher';
import type { UserService } from './UserService';
import type { SettingsService } from './SettingsService';
import type { AdminService } from './AdminService';
export const TOKENS = {
cacher: token<Cacher>('cacher'),
userService: token<UserService>('userService'),
settingsService: token<SettingsService>('settingsService'),
adminService: token<AdminService>('adminService'),
};

Creating tags:

tags.ts
import { tag } from 'brandi';
export const TAGS = {
offline: tag('offline'),
};

Creating two types of cacher with a common interface:

Cacher.ts
export interface Cacher {
/* ... */
}
export class OnlineCacher implements Cacher {
/* ... */
}
export class LocalCacher implements Cacher {
/* ... */
}

Creating some services with a dependency on the Cacher:

UserService.ts
import { injected } from 'brandi';
import { TOKENS } from './tokens';
import { Cacher } from './Cacher';
export class UserService {
constructor(private cacher: Cacher) {}
/* ... */
}
injected(UserService, TOKENS.cacher);
SettingsService.ts
import { injected } from 'brandi';
import { TOKENS } from './tokens';
import { Cacher } from './Cacher';
export class SettingsService {
constructor(private cacher: Cacher) {}
/* ... */
}
injected(SettingsService, TOKENS.cacher);
AdminService.ts
import { injected } from 'brandi';
import { TOKENS } from './tokens';
import { Cacher } from './Cacher';
export class AdminService {
constructor(private cacher: Cacher) {}
/* ... */
}
injected(AdminService, TOKENS.cacher);

Configuring the container:

container.ts
import { Container, tagged } from 'brandi';
import { TOKENS } from './tokens';
import { TAGS } from './tags';
import { OnlineCacher, LocalCacher } from './Cacher';
import { UserService } from './UserService';
import { SettingsService } from './SettingsService';
import { AdminService } from './AdminService';
tagged(SettingsService, TAGS.offline); /* โ† Tags `SettingsService`. */
export const container = new Container();
container
.bind(TOKENS.cacher) /* โ† Binds to `OnlineCacher` in common cases. */
.toInstance(OnlineCacher)
.inTransientScope();
container
.when(TAGS.offline) /* โ† Binds to `LocalCacher` when target tagget by `offline` tag. */
.bind(TOKENS.cacher)
.toInstance(LocalCacher)
.inTransientScope();
container
.when(AdminService) /* โ† Binds to `LocalCacher` when target is `AdminService`. */
.bind(TOKENS.cacher)
.toInstance(LocalCacher)
.inTransientScope();
container.bind(TOKENS.userService).toInstance(UserService).inTransientScope();
container.bind(TOKENS.settingsService).toInstance(SettingsService).inTransientScope();
container.bind(TOKENS.adminService).toInstance(AdminService).inTransientScope();

Dependencies are injected into services based on the tag:

index.ts
import { TOKENS } from './tokens';
import { OnlineCacher, LocalCacher } from './Cacher';
import { container } from './container';
const userService = container.get(TOKENS.userService);
const settingsService = container.get(TOKENS.settingsService);
const adminService = container.get(TOKENS.adminService);
expect(userService.cacher).toBeInstanceOf(OnlineCacher);
expect(settingsService.cacher).toBeInstanceOf(LocalCacher);
expect(adminService.cacher).toBeInstanceOf(LocalCacher);