vovaspace / brandi

The dependency injection container powered by TypeScript.
https://brandi.js.org
ISC License
193 stars 12 forks source link

Add async factories support #13

Closed daniel-white closed 3 years ago

daniel-white commented 3 years ago

Would it be possible to rework things so that container.get returns a Promise and toFactory takes a factory that returns a Promise to the type?

vovaspace commented 3 years ago

Hi. Do you mean something like this?

class Some {}

const TOKENS = {
  someAsyncFactory: token<Factory<Promise<Some>>>('AsyncFactory<Some>'),
};

const container = new Container();
container.bind(TOKENS.someAsyncFactory).toFactory(async () => { /* .. */ });

const someAsyncFactory = container.get(TOKENS.someAsyncFactory);
const someInstance = await someAsyncFactory();

Can you give an example of how you would like to use this in the context of your business logic? Thanks!

daniel-white commented 3 years ago

Yes. I'm using a 3rd party module that has some state it internally refreshes when I call an .refresh() that is an async method. I was trying to avoid calling that in the consuming code.

vovaspace commented 3 years ago

Hi @daniel-white!

I opened the PR with the addition of async factories. The main changes:

And it's all typed.

In your case, the logic can be implemented like this:

import { Container, AsyncFactory, token } from 'brandi';

class BusinessLogic { /* ... */ }

const TOKENS = {
  businessLogicFactory: token<AsyncFactory<BusinessLogic>>('AsyncFactory<BusinessLogic>'),
};

const container = new Container();

container
  .bind(TOKENS.businessLogicFactory)
  /*                              ↓ Returns a Promise. */
  .toFactory(BusinessLogic, () => thirdPartyInstance.refresh());

const businessLogicFactory = container.get(TOKENS.businessLogicFactory);

/*                    ↓ Will wait for the initializer to resolve. */
const businessLogic = await businessLogicFactory();

Is this exactly what you need?