Git Product home page Git Product logo

Comments (13)

steven166 avatar steven166 commented on August 23, 2024 8

In my opinion, you should be able to define the scope of the beans/tokens. For example, Spring has a couple of different scopes for beans, where the following 3 are the most relevant:

  • singleton (default): Scopes a single bean definition to a single object instance per Spring IoC container. (like typedi already does)
  • prototype: Scopes a single bean definition to any number of object instances. (like requested in this issue)
  • request: Scopes a single bean definition to the lifecycle of a single HTTP request; that is each and every HTTP request will have its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext. (related to this feature request: typestack/routing-controllers#174)

Here are examples how prototype and request scopes could be implemented with typeid (btw. I also likes @alexproca idea):

Prototype scope

import { Service, Scope } from "typedi"

@Service({ scope: Scope.Prototype })
class HandlerX implements Handler {} 

@Service({ scope: Scope.Prototype })
class HandlerY implements Handler {}
...
@Inject()
handlers: Handler[];

Request scope
Define tokens/beans

import { Service, Scope } from "typedi"

// Each request has its own TodoController instance
@Service({ scope: Scope.Request })
class TodoController {
  @Inject()
  todoService: TodoService;
} 

// Each request has its own TodoService instance
@Service({ scope: Scope.Request })
class TodoService {
  @Inject()
  todoRepo: TodoRepository;
} 

// All requests use the same repository instance
@Service({ scope: Scope.Singleton })
class TodoRepository {}

Initialize a new request scope

import { RequestContainer } from "typedi"

// create RequestContainer with a request context object, it inherit all tokens/beans from Container
let requestContainer = new RequestContainer( contextObject );
// get an instance for the current request
let todoController = requestScope.get( TodoController );

from typedi.

pleerock avatar pleerock commented on August 23, 2024 5

I've implemented this feature and released it in 0.6.0:

Using service groups

You can group multiple services into single group tagged with service id or token.
For example:

// Factory.ts
export interface Factory {
    create(): any;
}

// FactoryToken.ts
export const FactoryToken = new Token<Factory>("factories");

// BeanFactory.ts
@Service({ id: FactoryToken, multiple: true })
export class BeanFactory implements Factory {

    create() {
        console.log("bean created");
    }

}

// SugarFactory.ts
@Service({ id: FactoryToken, multiple: true })
export class SugarFactory implements Factory {

    create() {
        console.log("sugar created");
    }

}

// WaterFactory.ts
@Service({ id: FactoryToken, multiple: true })
export class WaterFactory implements Factory {

    create() {
        console.log("water created");
    }

}

// app.ts
// now you can get all factories in a single array 
const factories = Container.getMany(FactoryToken); // factories is Factory[]
factories.forEach(factory => factory.create());

Using multiple containers and scoped containers

By default all services are stored in the global service container,
and this global service container holds all unique instances of each service you have.

If you want your services to behave and store data inside differently,
based on some user context (http request for example) -
you can use different containers for different contexts.
For example:

// QuestionController.ts
@Service()
export class QuestionController {

    constructor(protected questionRepository: QuestionRepository) {
    }

    save() {
        this.questionRepository.save();
    }
}

// QuestionRepository.ts
@Service()
export class QuestionRepository {

    save() {
    }

}

// app.ts
const request1 = { param: "question1" };
const controller1 = Container.of(request1).get(QuestionController);
controller1.save("Timber");
Container.reset(request1);

const request2 = { param: "question2" };
const controller2 = Container.of(request2).get(QuestionController);
controller2.save("");
Container.reset(request2);

In this example controller1 and controller2 are completely different instances,
and QuestionRepository used in those controllers are different instances as well.

Container.reset removes container with the given context identifier.
If you want your services to be completely global and not be container-specific,
you can mark them as global:

@Service({ global: true })
export class QuestionUtils {
  
}

And this global service will be the same instance across all containers.

from typedi.

fjlucas avatar fjlucas commented on August 23, 2024 5

IMHO service groups has a problem. When you want to have several implementations of the same interface, most of the cases what you want at the end is to inject all them into an array in another class without having to know concrete implementations of that interface.

In this approach, you have to import all possible implemtantions what breaks the concept of DI and IOC. Any idea about how handling this scenario? Thanks!

from typedi.

ssljivic avatar ssljivic commented on August 23, 2024 2

For example:

@service('handler')
class HandlerX implements Handler {...}

@service('handler')
class HandlerY implements Handler {...}

...

@Inject('handler')
handlers: Handler[];

from typedi.

alexproca avatar alexproca commented on August 23, 2024 2

For starters what about

import { Container } from "typedi";

@service('handler')
class HandlerX implements Handler {...}

@service('handler')
class HandlerY implements Handler {...}

...

let allHandlera = Container.getAll(Handler)

And afterwards we can find a suitable way to use decorators for this functionality.

from typedi.

ssljivic avatar ssljivic commented on August 23, 2024 1

Any plans to support such a feature in the future? Most if not all DI frameworks support this kind of injection.

from typedi.

pleerock avatar pleerock commented on August 23, 2024

Can you provide an example of functionality you need?

from typedi.

pleerock avatar pleerock commented on August 23, 2024

no there is no such way, because each token holds single unique instance of the object

from typedi.

pleerock avatar pleerock commented on August 23, 2024

probably this can be implemented in the future. Need to start with a design proposal, simply @service('handler') wont work. We need to specify somehow that this service will work as an array of instances

from typedi.

tonivj5 avatar tonivj5 commented on August 23, 2024

I think it could be easier adding a multi property like angular's DI: https://angular.io/api/core/FactoryProvider#example-1

from typedi.

pleerock avatar pleerock commented on August 23, 2024

what @steven166 says does make sense, we'll need to implement this functionality

from typedi.

phryneas avatar phryneas commented on August 23, 2024

I'm also looking for something like this. Maybe it could be something like "tagged services"?

import { Container, Token } from "typedi";

export const HandlerTag= new Token<Handler>();

@Service
@Reflect.metadata("tag", HandlerTag)
class HandlerX implements Handler {...}

@Service
@Reflect.metadata("tag", HandlerTag)
class HandlerY implements Handler {...}

...

let allHandlers = Container.getTaggedServices(HandlerTag)

from typedi.

github-actions avatar github-actions commented on August 23, 2024

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

from typedi.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.