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);