### Organize Bindings with Container Modules in InversifyJS Source: https://context7.com/inversify/inversifyjs/llms.txt Demonstrates how to group related dependency bindings into reusable modules that can be loaded and unloaded from InversifyJS containers. This promotes modularity and code organization. It includes synchronous, asynchronous, and module unloading examples. ```typescript import 'reflect-metadata'; import { Container, ContainerModule, ContainerModuleLoadOptions, injectable, inject } from 'inversify'; @injectable() class Katana { public hit() { return 'cut!'; } } @injectable() class Shuriken { public throw() { return 'hit!'; } } @injectable() class Ninja { constructor( @inject('Katana') private katana: Katana, @inject('Shuriken') private shuriken: Shuriken ) {} public fight() { return this.katana.hit(); } public sneak() { return this.shuriken.throw(); } } // Define modules const weaponsModule = new ContainerModule( async (options: ContainerModuleLoadOptions) => { options.bind('Katana').to(Katana); options.bind('Shuriken').to(Shuriken); } ); const warriorsModule = new ContainerModule( async (options: ContainerModuleLoadOptions) => { options.bind('Ninja').to(Ninja); } ); // Async module with initialization const asyncModule = new ContainerModule( async (options: ContainerModuleLoadOptions) => { const config = await fetchConfig(); // async operation options.bind('Config').toConstantValue(config); } ); async function fetchConfig() { return { apiUrl: 'https://api.example.com' }; } // Usage const container = new Container(); // Load modules await container.load(weaponsModule, warriorsModule); const ninja = container.get('Ninja'); console.log(ninja.fight()); // Output: 'cut!' // Unload module - removes its bindings await container.unload(weaponsModule); // Now Katana and Shuriken are unbound console.log(container.isBound('Katana')); // Output: false ``` -------------------------------- ### InversifyJS Property Injection with Named and Tagged Constraints (TypeScript) Source: https://context7.com/inversify/inversifyjs/llms.txt Demonstrates property injection using the `@inject()` decorator on class properties. This example showcases how to use `@named()` and `@tagged()` decorators to apply specific constraints when resolving dependencies, allowing for multiple bindings of the same type. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, named, tagged } from 'inversify'; const TYPES = { Warrior: 'Warrior', Weapon: 'Weapon' }; const TAGS = { Primary: 'Primary', Secondary: 'Secondary' }; @injectable() class Katana { public name = 'Katana'; } @injectable() class Shuriken { public name = 'Shuriken'; } @injectable() class Samurai { // Property injection with named constraint @inject(TYPES.Weapon) @named(TAGS.Primary) public primaryWeapon!: Katana; // Property injection with tagged constraint @inject(TYPES.Weapon) @tagged('priority', TAGS.Secondary) public secondaryWeapon!: Shuriken; public name = 'Samurai'; } const container = new Container(); container.bind(TYPES.Warrior).to(Samurai); container.bind(TYPES.Weapon).to(Katana).whenNamed(TAGS.Primary); container.bind(TYPES.Weapon).to(Shuriken).whenTagged('priority', TAGS.Secondary); const warrior = container.get(TYPES.Warrior); console.log(warrior.primaryWeapon.name); // Output: 'Katana' console.log(warrior.secondaryWeapon.name); // Output: 'Shuriken' ``` -------------------------------- ### InversifyJS @injectable and @inject Decorators for Constructor Injection (TypeScript) Source: https://context7.com/inversify/inversifyjs/llms.txt Illustrates the use of `@injectable()` to mark classes for dependency injection and `@inject()` to specify which dependencies to inject into the constructor. This example shows injecting multiple dependencies of different types. ```typescript import 'reflect-metadata'; import { Container, injectable, inject } from 'inversify'; interface Weapon { hit(): string; } interface Throwable { throw(): string; } @injectable() class Katana implements Weapon { public hit() { return 'cut!'; } } @injectable() class Shuriken implements Throwable { public throw() { return 'hit!'; } } @injectable() class Ninja { private _katana: Weapon; private _shuriken: Throwable; constructor( @inject('Katana') katana: Weapon, @inject('Shuriken') shuriken: Throwable ) { this._katana = katana; this._shuriken = shuriken; } public fight() { return this._katana.hit(); } public sneak() { return this._shuriken.throw(); } } const container = new Container(); container.bind('Katana').to(Katana); container.bind('Shuriken').to(Shuriken); container.bind('Ninja').to(Ninja); const ninja = container.get('Ninja'); console.log(ninja.fight()); // Output: 'cut!' console.log(ninja.sneak()); // Output: 'hit!' ``` -------------------------------- ### InversifyJS Container Creation and Basic Binding (TypeScript) Source: https://context7.com/inversify/inversifyjs/llms.txt Demonstrates how to create and configure an InversifyJS container, including setting default scopes and parent-child relationships. It also shows basic registration of dependencies using symbols and strings, and resolving instances. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, bindingScopeValues } from 'inversify'; // Basic container creation const container = new Container(); // Container with singleton default scope const singletonContainer = new Container({ defaultScope: bindingScopeValues.Singleton }); // Child container with parent reference const parentContainer = new Container(); const childContainer = new Container({ parent: parentContainer }); // Service identifiers can be strings, symbols, or classes const TYPES = { Weapon: Symbol.for('Weapon'), Warrior: 'Warrior' }; @injectable() class Katana { public hit() { return 'cut!'; } } @injectable() class Ninja { constructor(@inject(TYPES.Weapon) private weapon: Katana) {} public fight() { return this.weapon.hit(); } } // Register bindings container.bind(TYPES.Weapon).to(Katana); container.bind(TYPES.Warrior).to(Ninja); // Resolve dependencies const ninja = container.get(TYPES.Warrior); console.log(ninja.fight()); // Output: 'cut!' ``` -------------------------------- ### InversifyJS Binding Scopes: Singleton, Transient, Request Source: https://context7.com/inversify/inversifyjs/llms.txt Illustrates how to control the lifecycle of dependencies using InversifyJS scopes. Demonstrates Singleton (single instance), Transient (new instance each time), and the default behavior. Requires 'reflect-metadata'. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, bindingScopeValues } from 'inversify'; @injectable() class Katana { private _usageCount = 0; public hit() { this._usageCount++; return `This katana was used ${this._usageCount} times!`; } } @injectable() class Shuriken { private _count = 10; public throw() { this._count--; return `Only ${this._count} items left!`; } } @injectable() class Ninja { constructor( @inject('Katana') public katana: Katana, @inject('Shuriken') public shuriken: Shuriken ) {} } const container = new Container(); container.bind('Ninja').to(Ninja); // Singleton scope - same instance shared container.bind('Katana').to(Katana).inSingletonScope(); // Transient scope (default) - new instance each time container.bind('Shuriken').to(Shuriken).inTransientScope(); const ninja1 = container.get('Ninja'); console.log(ninja1.katana.hit()); // Output: 'This katana was used 1 times!' console.log(ninja1.katana.hit()); // Output: 'This katana was used 2 times!' console.log(ninja1.shuriken.throw()); // Output: 'Only 9 items left!' const ninja2 = container.get('Ninja'); console.log(ninja2.katana.hit()); // Output: 'This katana was used 3 times!' (same katana) console.log(ninja2.shuriken.throw()); // Output: 'Only 9 items left!' (new shuriken) // Container with default singleton scope const singletonContainer = new Container({ defaultScope: bindingScopeValues.Singleton }); ``` -------------------------------- ### Create Factory Dependencies with toFactory in TypeScript Source: https://context7.com/inversify/inversifyjs/llms.txt Demonstrates how to use `toFactory` to create factory functions that can produce dependencies with custom logic or parameters at runtime. This is useful for scenarios where dependencies need to be created with specific configurations or based on runtime conditions. It requires the `reflect-metadata` polyfill. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, Factory, ResolutionContext } from 'inversify'; interface Weapon { name: string; damage: number; } @injectable() class Sword implements Weapon { public name = 'Sword'; public damage = 10; } @injectable() class Katana implements Weapon { public name = 'Katana'; public damage = 20; } @injectable() class Ninja { constructor( @inject('WeaponFactory') private weaponFactory: (type: string) => Weapon ) {} public getWeapon(type: string): Weapon { return this.weaponFactory(type); } } const container = new Container(); container.bind('Weapon').to(Sword).whenNamed('sword'); container.bind('Weapon').to(Katana).whenNamed('katana'); container.bind('Ninja').to(Ninja); // Factory with parameters container.bind>('WeaponFactory').toFactory( (context: ResolutionContext) => (type: string) => { return context.get('Weapon', { name: type }); } ); const ninja = container.get('Ninja'); const sword = ninja.getWeapon('sword'); const katana = ninja.getWeapon('katana'); console.log(sword.name, sword.damage); // Output: 'Sword' 10 console.log(katana.name, katana.damage); // Output: 'Katana' 20 // Factory with tagged constraints container.bind>('TaggedWeaponFactory').toFactory( (context: ResolutionContext) => (throwable: boolean) => { return context.get('Weapon', { tag: { key: 'throwable', value: throwable } }); } ); ``` -------------------------------- ### Programmatic Decorator Application in InversifyJS (JavaScript) Source: https://context7.com/inversify/inversifyjs/llms.txt Shows how to use the `decorate` function in InversifyJS to apply decorators programmatically, which is useful in vanilla JavaScript or environments where decorator syntax is not directly supported. It demonstrates applying `@injectable` and `@inject` decorators to classes and constructor/setter parameters. ```javascript import 'reflect-metadata'; import { Container, injectable, inject, decorate } from 'inversify'; // Classes without decorator syntax class Katana { public hit() { return 'cut!'; } } class Shuriken { public throw() { return 'hit!'; } } class Blowgun { public blow() { return 'poison!'; } } class Ninja { public katana: Katana; public shuriken: Shuriken; public blowgun!: Blowgun; constructor(katana: Katana, shuriken: Shuriken) { this.katana = katana; this.shuriken = shuriken; } public set blowgunSetter(blowgun: Blowgun) { this.blowgun = blowgun; } } const TYPES = { Ninja: 'Ninja', Katana: 'Katana', Shuriken: 'Shuriken', Blowgun: 'Blowgun' }; // Apply @injectable() to classes decorate([injectable()], Katana); decorate([injectable()], Shuriken); decorate([injectable()], Blowgun); decorate([injectable()], Ninja); // Apply @inject() to constructor parameters (by index) decorate([inject(TYPES.Katana)], Ninja, 0); decorate([inject(TYPES.Shuriken)], Ninja, 1); // Apply @inject() to setter (by property name) decorate([inject(TYPES.Blowgun)], Ninja, 'blowgunSetter'); const container = new Container(); container.bind(TYPES.Ninja).to(Ninja); container.bind(TYPES.Katana).to(Katana); container.bind(TYPES.Shuriken).to(Shuriken); container.bind(TYPES.Blowgun).to(Blowgun); const ninja = container.get(TYPES.Ninja); console.log(ninja.katana.hit()); // Output: 'cut!' console.log(ninja.shuriken.throw()); // Output: 'hit!' console.log(ninja.blowgun.blow()); // Output: 'poison!' ``` -------------------------------- ### Create Async Provider Dependencies with toProvider in TypeScript Source: https://context7.com/inversify/inversifyjs/llms.txt Illustrates how to use `toProvider` for creating asynchronous provider functions, suitable for complex initialization or lazy loading scenarios. This method allows for deferred dependency creation and can handle asynchronous operations before resolving the dependency. It also requires the `reflect-metadata` polyfill. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, ResolutionContext } from 'inversify'; @injectable() class Ninja { public level = 0; public async train(): Promise { return new Promise(resolve => { setTimeout(() => { this.level += 10; resolve(this.level); }, 100); }); } } @injectable() class NinjaMaster { public rank = 'NinjaMaster'; } type NinjaMasterProvider = () => Promise; const container = new Container(); container.bind('Ninja').to(Ninja).inSingletonScope(); // Provider that creates NinjaMaster only after training container.bind('Provider').toProvider( (context: ResolutionContext) => async () => { return new Promise((resolve, reject) => { const ninja = context.get('Ninja'); ninja.train().then(level => { if (level >= 20) { resolve(new NinjaMaster()); } else { reject('Not enough training'); } }); }); } ); // Usage const provider = container.get('Provider'); // First call - level becomes 10, fails provider() .then(master => console.log(master.rank)) .catch(err => console.log(err)); // Output: 'Not enough training' // Second call - level becomes 20, succeeds provider() .then(master => console.log(master.rank)) // Output: 'NinjaMaster' .catch(err => console.log(err)); ``` -------------------------------- ### Hierarchical Containers with InversifyJS Source: https://context7.com/inversify/inversifyjs/llms.txt Demonstrates creating parent and child containers where child containers inherit bindings from their parents. It shows how to access bindings from parent containers and how child containers can override parent bindings. This is useful for organizing dependencies in larger applications. ```typescript import 'reflect-metadata'; import { Container, injectable, inject } from 'inversify'; @injectable() class Katana { public name = 'Katana'; } @injectable() class Shuriken { public name = 'Shuriken'; } @injectable() class SuperKatana { public name = 'SuperKatana'; } // Create parent container const parentContainer = new Container(); parentContainer.bind('Weapon').to(Katana); // Create child container const childContainer = new Container({ parent: parentContainer }); childContainer.bind('Throwable').to(Shuriken); // Create grandchild container const grandchildContainer = new Container({ parent: childContainer }); grandchildContainer.bind('Weapon').to(SuperKatana); // Child can access parent bindings const weaponFromChild = childContainer.get('Weapon'); console.log(weaponFromChild.name); // Output: 'Katana' // Check if bound in current container only console.log(childContainer.isBound('Weapon')); // true (from parent) console.log(childContainer.isCurrentBound('Weapon')); // false (not in current) console.log(childContainer.isCurrentBound('Throwable')); // true (in current) // Grandchild overrides parent binding const weaponFromGrandchild = grandchildContainer.get('Weapon'); console.log(weaponFromGrandchild.name); // Output: 'SuperKatana' // Grandchild still has access to parent chain const throwable = grandchildContainer.get('Throwable'); console.log(throwable.name); // Output: 'Shuriken' ``` -------------------------------- ### Snapshot and Restore Container State in InversifyJS Source: https://context7.com/inversify/inversifyjs/llms.txt Demonstrates how to save and restore the state of an InversifyJS container. This is useful for testing scenarios or dynamic reconfiguration of bindings. It shows creating snapshots, restoring to the previous state, and managing a stack of snapshots. ```typescript import 'reflect-metadata'; import { Container, injectable } from 'inversify'; @injectable() class ProductionService { public name = 'Production'; } @injectable() class MockService { public name = 'Mock'; } const container = new Container(); container.bind('Service').to(ProductionService); // Get production service let service = container.get('Service'); console.log(service.name); // Output: 'Production' // Take snapshot before testing container.snapshot(); // Replace with mock for testing await container.unbind('Service'); container.bind('Service').to(MockService); service = container.get('Service'); console.log(service.name); // Output: 'Mock' // Restore original bindings container.restore(); service = container.get('Service'); console.log(service.name); // Output: 'Production' // Multiple snapshots create a stack container.snapshot(); // v1 await container.unbind('Service'); container.snapshot(); // v2 container.restore(); // back to v2 container.restore(); // back to v1 // Throws if no more snapshots try { container.restore(); } catch (e) { console.log('No more snapshots'); } ``` -------------------------------- ### Apply Cache Provider in InversifyJS (TypeScript) Source: https://github.com/inversify/inversifyjs/wiki/Idea-Backlog Demonstrates how to apply a cache provider to the InversifyJS kernel and configure caching for a specific binding. This can improve performance by reducing the need to resolve dependencies repeatedly. It requires the InversifyJS library and a compatible caching mechanism. ```typescript let kernel = new Kernel(); kernel.applyCacheProvider(); kernel.bind("T").to(T).withCache({ stdTTL: 100, checkperiod: 120 }); ``` -------------------------------- ### InversifyJS: @optional for Optional Dependencies and Default Values Source: https://context7.com/inversify/inversifyjs/llms.txt Explains how to use the @optional decorator in InversifyJS to mark dependencies as optional, allowing resolution even if no binding exists. It also shows how to provide default values for these optional dependencies, both in constructor injection and property injection. Requires 'reflect-metadata'. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, optional } from 'inversify'; @injectable() class Katana { public name = 'Katana'; } @injectable() class Shuriken { public name = 'Shuriken'; } @injectable() class Ninja { public name = 'Ninja'; public katana: Katana; public shuriken: Shuriken; constructor( @inject('Katana') katana: Katana, @inject('Shuriken') @optional() shuriken: Shuriken = { name: 'DefaultShuriken' } ) { this.katana = katana; this.shuriken = shuriken; } } // Property injection with optional and default value @injectable() class Samurai { @inject('Katana') @optional() public katana: Katana = { name: 'DefaultKatana' }; } const container = new Container(); container.bind('Katana').to(Katana); container.bind('Ninja').to(Ninja); container.bind('Samurai').to(Samurai); // Note: Shuriken is NOT bound const ninja = container.get('Ninja'); console.log(ninja.katana.name); // Output: 'Katana' console.log(ninja.shuriken.name); // Output: 'DefaultShuriken' // After binding Shuriken container.bind('Shuriken').to(Shuriken); const ninja2 = container.get('Ninja'); console.log(ninja2.shuriken.name); // Output: 'Shuriken' // Optional get at container level const maybeWeapon = container.get('NonExistent', { optional: true }); console.log(maybeWeapon); // Output: undefined ``` -------------------------------- ### Activation and Deactivation Hooks in InversifyJS Source: https://context7.com/inversify/inversifyjs/llms.txt Shows how to define custom logic that executes when instances are created (activated) or disposed (deactivated) using the `onActivation` and `onDeactivation` methods. This is useful for managing resources like database connections or performing cleanup tasks. Hooks can be defined at the binding level or the container level. ```typescript import 'reflect-metadata'; import { Container, injectable, ResolutionContext } from 'inversify'; @injectable() class DatabaseConnection { public isConnected = false; public connect() { this.isConnected = true; console.log('Database connected'); } public disconnect() { this.isConnected = false; console.log('Database disconnected'); } } const container = new Container(); // Binding with activation hook container .bind('Database') .to(DatabaseConnection) .inSingletonScope() .onActivation((context: ResolutionContext, db: DatabaseConnection) => { db.connect(); return db; }) .onDeactivation((db: DatabaseConnection) => { db.disconnect(); }); // Container-level activation hook container.onActivation( 'Database', (context: ResolutionContext, db: DatabaseConnection) => { console.log('Database instance activated'); return db; } ); // Container-level deactivation hook container.onDeactivation( 'Database', (db: DatabaseConnection) => { console.log('Database instance deactivated'); } ); // Get instance - triggers activation const db = container.get('Database'); // Output: 'Database connected' // Output: 'Database instance activated' console.log(db.isConnected); // Output: true // Unbind triggers deactivation for singletons await container.unbind('Database'); // Output: 'Database instance deactivated' // Output: 'Database disconnected' ``` -------------------------------- ### InversifyJS: Named and Tagged Bindings for Disambiguation Source: https://context7.com/inversify/inversifyjs/llms.txt Demonstrates how to use named and tagged constraints in InversifyJS to differentiate between multiple implementations of the same interface. This is useful when a class needs to inject different versions of a dependency based on specific criteria. It requires the 'reflect-metadata' polyfill. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, named, tagged } from 'inversify'; interface Weapon { name: string; } @injectable() class Katana implements Weapon { public name = 'katana'; } @injectable() class Shuriken implements Weapon { public name = 'shuriken'; } @injectable() class Ninja { constructor( @inject('Weapon') @named('melee') public meleeWeapon: Weapon, @inject('Weapon') @tagged('canThrow', true) public throwableWeapon: Weapon ) {} } const container = new Container(); container.bind('Ninja').to(Ninja); // Named bindings container.bind('Weapon').to(Katana).whenNamed('melee'); container.bind('Weapon').to(Shuriken).whenNamed('ranged'); // Tagged bindings container.bind('Weapon').to(Katana).whenTagged('canThrow', false); container.bind('Weapon').to(Shuriken).whenTagged('canThrow', true); // Resolve with named constraint const katana = container.get('Weapon', { name: 'melee' }); const shuriken = container.get('Weapon', { name: 'ranged' }); console.log(katana.name); // Output: 'katana' console.log(shuriken.name); // Output: 'shuriken' // Resolve with tagged constraint const tagged1 = container.get('Weapon', { tag: { key: 'canThrow', value: false } }); const tagged2 = container.get('Weapon', { tag: { key: 'canThrow', value: true } }); console.log(tagged1.name); // Output: 'katana' console.log(tagged2.name); // Output: 'shuriken' ``` -------------------------------- ### Apply Contextual Bindings with whenParent and whenAnyAncestor in InversifyJS Source: https://context7.com/inversify/inversifyjs/llms.txt Illustrates how to use InversifyJS contextual binding constraints, specifically `whenParent` and `whenAnyAncestor`, to conditionally resolve dependencies based on their position in the dependency tree. This allows for more sophisticated dependency injection strategies. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, BindingConstraints } from 'inversify'; interface Material { name: string; } @injectable() class Wood implements Material { public name = 'wood'; } @injectable() class Iron implements Material { public name = 'iron'; } @injectable() class Sword { constructor(@inject('Material') public material: Material) {} } @injectable() class NinjaStudent { constructor(@inject('Weapon') public weapon: Sword) {} } @injectable() class NinjaMaster { constructor(@inject('Weapon') public weapon: Sword) {} } const container = new Container(); // Bind warriors with tags container.bind('Ninja').to(NinjaStudent).whenTagged('master', false); container.bind('Ninja').to(NinjaMaster).whenTagged('master', true); // Bind weapon container.bind('Weapon').to(Sword); // Different materials based on ancestor container.bind('Material').to(Iron).whenAnyAncestorTagged('master', true); container.bind('Material').to(Wood).whenAnyAncestorTagged('master', false); // Custom ancestor constraint function isNinjaMaster(constraints: BindingConstraints): boolean { return constraints.serviceIdentifier === 'Ninja' && constraints.tags.get('master') === true; } container.bind('PremiumMaterial').to(Iron).whenAnyAncestor(isNinjaMaster); // Resolve const master = container.get('Ninja', { tag: { key: 'master', value: true } }); const student = container.get('Ninja', { tag: { key: 'master', value: false } }); console.log(master.weapon.material.name); // Output: 'iron' console.log(student.weapon.material.name); // Output: 'wood' ``` -------------------------------- ### Async Dependency Resolution in InversifyJS Source: https://context7.com/inversify/inversifyjs/llms.txt Illustrates how to resolve dependencies asynchronously using `getAsync` and `getAllAsync` in InversifyJS. This is essential when bindings involve asynchronous operations, such as fetching configuration or data. It covers single and multiple async resolutions, including named bindings and optional resolution. ```typescript import 'reflect-metadata'; import { Container, injectable, ResolutionContext } from 'inversify'; interface Config { apiUrl: string; timeout: number; } const container = new Container(); // Async dynamic value binding container.bind('Config').toDynamicValue( async (context: ResolutionContext) => { // Simulate async config loading return new Promise(resolve => { setTimeout(() => { resolve({ apiUrl: 'https://api.example.com', timeout: 5000 }); }, 100); }); } ); // Multiple async bindings container.bind('Message').toDynamicValue( async () => Promise.resolve('Hello') ).whenNamed('greeting'); container.bind('Message').toDynamicValue( async () => Promise.resolve('Goodbye') ).whenNamed('farewell'); // Async resolution async function main() { // Single async get const config = await container.getAsync('Config'); console.log(config.apiUrl); // Output: 'https://api.example.com' // Async get with named constraint const greeting = await container.getAsync('Message', { name: 'greeting' }); console.log(greeting); // Output: 'Hello' // Get all async bindings const messages = await container.getAllAsync('Message'); console.log(messages); // Output: ['Hello', 'Goodbye'] // Optional async get const optional = await container.getAsync('NonExistent', { optional: true }); console.log(optional); } main(); ``` -------------------------------- ### InversifyJS Binding Types: to, toSelf, toConstantValue, toDynamicValue Source: https://context7.com/inversify/inversifyjs/llms.txt Demonstrates different ways to bind dependencies in InversifyJS. Includes binding interfaces to implementations, classes to themselves, constant values, and dynamically computed values. Requires 'reflect-metadata'. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, ResolutionContext } from 'inversify'; @injectable() class Katana { public hit() { return 'cut!'; } } @injectable() class Hero { public name: string; constructor() { this.name = 'superman'; } } const container = new Container(); // Bind interface to implementation container.bind('Weapon').to(Katana); // Bind class to itself container.bind(Hero).toSelf(); // Bind to a constant value (singleton) const heroInstance = new Hero(); heroInstance.name = 'batman'; container.bind('ConstantHero').toConstantValue(heroInstance); // Bind to dynamic value - computed each time container.bind('UniqueId').toDynamicValue( (context: ResolutionContext) => Symbol() ); // Bind to async dynamic value container.bind('AsyncConfig').toDynamicValue( async (context: ResolutionContext) => { return Promise.resolve('loaded-config'); } ); // Usage const weapon = container.get('Weapon'); const hero = container.get(Hero); const constantHero = container.get('ConstantHero'); const id1 = container.get('UniqueId'); const id2 = container.get('UniqueId'); console.log(weapon.hit()); // Output: 'cut!' console.log(hero.name); // Output: 'superman' console.log(constantHero.name); // Output: 'batman' console.log(id1 === id2); // Output: false (new symbol each time) ``` -------------------------------- ### Lifecycle Hooks (@postConstruct, @preDestroy) in InversifyJS Source: https://context7.com/inversify/inversifyjs/llms.txt Demonstrates using the `@postConstruct` and `@preDestroy` decorators to define methods that are automatically called after an instance is constructed and before it is destroyed, respectively. These decorators simplify managing initialization and cleanup logic within classes, especially for singletons. ```typescript import 'reflect-metadata'; import { Container, injectable, postConstruct, preDestroy } from 'inversify'; @injectable() class Service { public initialized = false; public destroyed = false; @postConstruct() public init() { this.initialized = true; console.log('Service initialized'); } @preDestroy() public cleanup() { this.destroyed = true; console.log('Service cleaned up'); } public doWork() { return 'Working...'; } } const container = new Container(); container.bind('Service').to(Service).inSingletonScope(); // Get instance - @postConstruct is called const service = container.get('Service'); // Output: 'Service initialized' console.log(service.initialized); // Output: true console.log(service.doWork()); // Output: 'Working...' // Unbind singleton - @preDestroy is called await container.unbind('Service'); // Output: 'Service cleaned up' ``` -------------------------------- ### Support Inheritance with @injectFromBase in TypeScript Source: https://context7.com/inversify/inversifyjs/llms.txt Illustrates how to use the `@injectFromBase` decorator in InversifyJS to allow derived classes to inherit injectable metadata from their base classes. This simplifies dependency injection in class hierarchies. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, injectFromBase, tagged, unmanaged } from 'inversify'; const TYPES = { Warrior: 'Warrior', Weapon: 'Weapon' }; const TAGS = { Primary: 'Primary', Secondary: 'Secondary' }; interface Weapon { name: string; } @injectable() class Katana implements Weapon { public name = 'Katana'; } @injectable() class Shuriken implements Weapon { public name = 'Shuriken'; } // Base class with injected property @injectable() class BaseWarrior { @inject(TYPES.Weapon) @tagged('priority', TAGS.Primary) public primaryWeapon!: Weapon; public name: string; constructor(@unmanaged() name: string) { this.name = name; } } // Derived class inherits base class injections @injectable() @injectFromBase({ extendConstructorArguments: false, extendProperties: true }) class Samurai extends BaseWarrior { @inject(TYPES.Weapon) @tagged('priority', TAGS.Secondary) public secondaryWeapon!: Weapon; constructor() { super('Samurai'); } } const container = new Container(); container.bind(TYPES.Warrior).to(Samurai); container.bind(TYPES.Weapon).to(Katana).whenTagged('priority', TAGS.Primary); container.bind(TYPES.Weapon).to(Shuriken).whenTagged('priority', TAGS.Secondary); const samurai = container.get(TYPES.Warrior); console.log(samurai.name); // Output: 'Samurai' console.log(samurai.primaryWeapon.name); // Output: 'Katana' (inherited) console.log(samurai.secondaryWeapon.name); // Output: 'Shuriken' ``` -------------------------------- ### Handle Circular Dependencies with LazyServiceIdentifier in TypeScript Source: https://context7.com/inversify/inversifyjs/llms.txt Demonstrates how to resolve circular dependencies in InversifyJS by using `LazyServiceIdentifier`. This defers the resolution of service identifiers until runtime, preventing issues when services depend on each other. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, LazyServiceIdentifier } from 'inversify'; const TYPES = { Ninja: Symbol.for('Ninja'), Weapon: Symbol.for('Weapon') }; @injectable() class Katana { public hit() { return 'cut!'; } } @injectable() class Ninja { constructor( @inject(new LazyServiceIdentifier(() => TYPES.Weapon)) private weapon: Katana ) {} public fight() { return this.weapon.hit(); } } const container = new Container(); container.bind(TYPES.Ninja).to(Ninja); container.bind(TYPES.Weapon).to(Katana); const ninja = container.get(TYPES.Ninja); console.log(ninja.fight()); // Output: 'cut!' ``` -------------------------------- ### InversifyJS: @multiInject for Injecting Multiple Values Source: https://context7.com/inversify/inversifyjs/llms.txt Illustrates the use of the @multiInject decorator in InversifyJS to inject all registered bindings for a given service identifier as an array. This is useful when a class needs to consume multiple instances of the same type. It requires the 'reflect-metadata' polyfill. ```typescript import 'reflect-metadata'; import { Container, injectable, inject, multiInject } from 'inversify'; interface Weapon { name: string; } @injectable() class Katana implements Weapon { public name = 'Katana'; } @injectable() class Shuriken implements Weapon { public name = 'Shuriken'; } @injectable() class Nunchaku implements Weapon { public name = 'Nunchaku'; } @injectable() class Ninja { public weapons: Weapon[]; constructor(@multiInject('Weapon') weapons: Weapon[]) { this.weapons = weapons; } public showArsenal() { return this.weapons.map(w => w.name).join(', '); } } const container = new Container(); container.bind('Ninja').to(Ninja); container.bind('Weapon').to(Katana); container.bind('Weapon').to(Shuriken); container.bind('Weapon').to(Nunchaku); const ninja = container.get('Ninja'); console.log(ninja.showArsenal()); // Output: 'Katana, Shuriken, Nunchaku' // getAll returns all bindings for identifier const allWeapons = container.getAll('Weapon'); console.log(allWeapons.length); // Output: 3 ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.