typestack / typedi Goto Github PK
View Code? Open in Web Editor NEWSimple yet powerful dependency injection tool for JavaScript and TypeScript.
Home Page: https://docs.typestack.community/typedi/v/develop/01-getting-started
License: MIT License
Simple yet powerful dependency injection tool for JavaScript and TypeScript.
Home Page: https://docs.typestack.community/typedi/v/develop/01-getting-started
License: MIT License
I will list issues later. If anyone could help with PR, that would be nice.
Hello there,
I would like to test my controller (routing-controllers) but i don't really know how to.
Typedi is supposed to work like Angular2+ inject or similar.
But when i use Container.set to override my model's method used by the controller it's seems to be broken.
I need some hint to know how to do that.
I think i do not test my controller like expected or maybe i don't really understand Typedi Container and @service injection implementation.
It's supposed to be usefull to avoid to mock db connection.
Thx a lot.
My spec
import 'reflect-metadata';
import { Application } from 'express';
import request from 'supertest';
import { createExpressServer, useContainer as useContainerRouting } from 'routing-controllers';
import { Container } from 'typedi';
import { ExampleController } from '../controllers/example.controller';
import { ExampleRepository } from '../repositories/example.repository';
import { ExampleModel } from '../models/example.model';
describe('GET', () => {
let app: Application | null;
beforeEach((_done: jest.DoneCallback) => {
useContainerRouting(Container);
});
afterEach((_done: jest.DoneCallback) => {
Container.reset();
app = null;
});
it('should call model with proper id and returns model response', async () => {
const EXAMPLE_ID_TEST: number = 1;
app = createExpressServer({
cors: true,
controllers: [
ExampleController
]
});
@Service()
class TestModel {
public getExampleById: any = jest.fn().mockImplementation((_id: number) => new Promise((resolve: any) => resolve({})));
}
Container.set(ExampleModel, new TestModel());
const res: request.Response = await request(app).get(`/example/${EXAMPLE_ID_TEST}`);
expect(res.body).toEqual({});
});
My controller
import { ExampleModel } from '../models/example.model';
import { TableTest } from '../entities/tabletest.entity';
import { JsonController, Get } from 'routing-controllers';
@JsonController('/example')
export class ExampleController {
constructor(
private readonly model: ExampleModel) {
}
@Get('/:id')
public async getExample(@Param('id') id: number): Promise<TableTest> {
return this.model.getExampleById(id);
}
}
My Model
import { TableTest } from '../entities/tabletest.entity';
import { Service } from 'typedi';
import { OrmRepository } from 'typeorm-typedi-extensions';
import { NotFoundError } from 'routing-controllers';
import { ExampleRepository } from '../repositories/example.repository';
@Service()
export class ExampleModel {
constructor(
@OrmRepository()
private readonly repository: ExampleRepository) {
}
public async getExampleById(id: number): Promise<TableTest> {
const example: TableTest | undefined = await this.repository.findOneById(id);
if (example === undefined) {
throw new NotFoundError(`Example ${id} not found`);
}
return example;
}
}
Hi,
Awesome library. I really like it. 👍
However, I am wondering how can I declare a services as transient?
Cheers,
Gery
I use empty @Service()
and @Inject()
, so raise an error TypeError: Cannot read property 'bind' of undefined
I add a name to both then they work fine.
typedi 0.4.2
node 6.2.1
Hi there,
I don't know how to inject Request/Session object into service classes.
Here is what i do and does not work :
LocalisationFactory.ts:
import {Inject,Service} from "typedi";
import {Request} from "express";
import { Localisation } from "./Localisation";
@Service()
export class LocalisationFactory
{
@Inject()
request: Request;
create()
{
let instance = new Localisation();
instance.setRequest(this.request);
return instance;
}
}
Hello!
Thank you for this great module!
However, is it possible to instantiate services by calling a factory function instead of the constructor of the specified class?
I know, you can use Container.provide()
to add instances directly to the container, but this will force us to instantiate all instances during container initialization stage. The better approach would be to provide a factory function, which will be called by the container when the instance is first requested from it (i.e. lazy instantiation).
Here's the example of the desired code:
// The "Bus" class is registered, but not yet instantiated.
// Factory function is specified by the "factory" property.
Container.provide([{
type: Bus,
factory: BusFactory.create
}]);
// The "Bus" class is instantiated by calling
// the "BusFactory.create" factory, then instance is returned.
// Without this call, "Bus" will never be instantiated.
const bus = Container.get(Bus);
bus.drive();
// Bus factory is responsible for creating new buses.
class BusFactory {
// Logger instance should be injected by DI container automatically.
public static create (Logger: logger) {
logger.debug('Creating a new Bus');
return new Bus();
}
}
class Bus {
constructor (private Logger: logger) {
logger.debug('Bus is created');
}
drive () {
this.logger.debug('Bus is moving');
}
}
Also, the factory function itself must be able to rely on values injected by DI container.
Right now, I'm using Angular 2 DI Container in my Node.js application (it supports factory functions), but it's API is somewhat cumbersome and limited. I really like the API of your Container, especially the use of annotations, but lack of the factory functions support is stopping me from migrating.
Also, here's how this implemented in Symfony: Using a Factory to Create Services.
Are you planning to add support for factory functions? Or have I somehow missed it? Or could you recommend some workarounds?
Thanks!
First off, I love this project, it's been incredible.
I'm having a slight issue and was wondering If I could get some insight as it's probably a me issue.
Below is a small snippet of what I have.
// Whitelist.ts
@Service()
export class Whitelist extends Rule {
entries: Set<string>;
setup(entries: WhitelistEntryFragment[]) {
this.entries = new Set(entries.map(entry => entry.value));
}
}
// rule.ts
@Service()
export class Rule {
id: number;
name: string;
enabled: boolean;
silent: boolean;
settings: any;
responses: Responses[];
@Inject('logger')
logger: LoggerInterface;
static parseRule(rule: RuleFragment): RuleInterface {
return Object.assign({}, rule, {
responses: rule.responses.map<Responses>(response => response.value)
});
}
}
However when I run the following
const whitelist = Container.get(Whitelist);
console.log(whitelist);
whitelist.setup(
data.channel.whitelist
);
The log returns only
Rule {
logger:
ConsoleLogger {
loggingLevel: 'trace',
trace: [Function],
debug: [Function],
info: [Function],
warn: [Function],
error: [Function],
fatal: [Function] } }
[13:49] error: TypeError: whitelist.setup is not a function
Any help would be appreciated here. I'm guessing I'm missing some really basic concept here but I've been lost for about an hour now 👎
I have a service
@Service()
export class Discuz {
...
}
While I want to inject it in customRepository, however it seems no work.
@Service()
@EntityRepository(User)
export class UserRepository extends Repository<User> {
@Inject()
discuz: Discuz
async loginDiscuz (cookies: {}, body: {}) {
console.log(this.discuz, Container.get(Discuz)) // This output undefined Discuz {}
}
}
But this work:
@Service()
export class UserService {
@OrmCustomRepository(UserRepository)
userRepository: UserRepository
@Inject()
discuz: Discuz
async loginDiscuz (cookies: {}, body: {}): Promise<{ accessToken: string }> {
console.log(this.discuz) // output Discuz {}
return this.userRepository.loginDiscuz(cookies, body)
}
}
Maybe @EntityRepository
breaks the typedi?
As discussed here: #11 (comment) we want to move from a single static container to a named instantiable ones.
Here's the desired API:
// Returns container instance of the default container:
const container1 = Container.get();
// Returns container instance of the second container.
// The additional container which goes under the "second-container" name.
const container2 = Container.get("second-container");
// This service belongs to the default container.
@Service()
class Foo {
}
// Or more meaningful API:
@Service({
name: "bar",
container: "second-container"
})
class Bar {
}
Right now the behavior is to inject undefined
when a service requests an absent binding. This defeats the purpose of a type system as it opens the door for sneaky errors in the middle of a sound method.
After doing some research, I found that it's most likely a bug which happens when requiring a service by its type:
Here is what I mean expressed as a test case:
it("should throw if the object was not set", () => {
class Unregistered { }
// Both assertions should pass but only the first one does:
expect(() => Container.get("unregistered")).to.throw();
expect(() => Container.get(Unregistered)).to.throw();
});
Is there a way to inject all service instances (e.g. named services) into an array?
This is a "must have" feature, but I could not find anything in the docs.
In the sample8-tokenized-services
the services are registered via Container.set
. I tried it with a @Service(StoreService)
decorator at FtpStore
, but that don't work.
Shouldn't I be able to register services with a token via a decorator like stated in the readme?
https://github.com/typestack/typedi#services-with-token-name
ServiceNotFoundError: Service with a given token was not found, looks like it was not registered in the container. Register it by calling Container.set before using service.
Hey,
im having trouble to get Interface Injection working, here is an example:
import {Token, Container, Service, Inject} from 'typedi'
declare interface IFoo {
foo(): void
}
const FooImpl = new Token<IFoo>()
@Service(FooImpl)
class Foo implements IFoo {
foo (): void {
return
}
}
@Service()
class Bar {
@Inject(FooImpl) //throws "Argument of type 'Token<FooImpl>' is not assignable to parameter of type 'string'."
private foo: IFoo
}
console.log(Container.get<Bar>(Bar))
here is my tsconfig :
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"outDir": "dist",
"inlineSourceMap": true,
"declaration": true,
"lib": ["es6"],
"removeComments": true,
"preserveConstEnums": true,
"moduleResolution": "node",
"types": [
"node",
"reflect-metadata"
]
},
"exclude": [
],
"typeRoots": [
"node_modules/@types"
],
"include": [
"src/**/*.ts",
"tests/**/*.ts",
"node_modules/typedi/**/*.ts"
]
}
where is my error?
I'm using the following code:
import {Service} from 'typedi';
import {OrmManager, OrmRepository} from 'typeorm-typedi-extensions';
import {EntityManager, Repository} from 'typeorm';
import {schools} from '../entities/schools';
@Service()
export class SchoolRepository {
@OrmManager()
private entityManager: EntityManager;
constructor(@OrmRepository(schools) private ormRepository: Repository<schools>) {
}
saveUsingRepository(post: schools) {
return this.ormRepository.save(post);
}
saveUsingManager(post: schools) {
return this.entityManager.save(post);
}
findAll() {
return this.ormRepository.find({cache: 60000, take: 100});
}
}
Then I use this code the get this repository:
import {JsonController, Get, QueryParam} from 'routing-controllers';
import {SchoolRepository} from '../repository/SchoolRepository';
import {Container, Service} from 'typedi';
@Service()
@JsonController()
export class SchoolsController {
constructor(private repository: SchoolRepository){
//is null... :C
}
@Get("/schools")
get(@QueryParam("page") page: number = 0) {
return this.repository.findAll();
}
}
The repository is always null, the only time when it returns the class is when I use this: Container.get(SchoolRepository);
Hi @pleerock typescript cannot build because of a property does not exists when injecting to a constructor. Here's the link of sample repository https://github.com/cedrickmandocdoc/typedi-bug
How can we prevent this typescript error with preserving types? I am aware that there is workaround but I should ask if this can be a typedi bug.
Hi,
What's the correct way to use factory services.
Usually, (in my Php projects), i'm using a service locator.
Ex:
public function createService(ServiceLocatorInterface $serviceLocator)
{
$config = $serviceLocator->get('Config');
$om = $serviceLocator->get('om');
$abonnementMapper = $om->getRepository('Membre\Entity\MembreAbonnement');
$instance = new AbonnementService();
$instance->setAbonnementMapper($abonnementMapper);
return $instance;
}
Can you tell me how to do such a thing with TypeDi ?
David
This is a proposal of feature. Should it get attention I can work on this.
The problem is simple, I think that when dependency can't be satisfied (either it doesn't exist or one of its own dependencies wasn't found) the DI container should exit saying it couldn't build the dependency tree or throw an error. When using string-based tokens it is easy to miss something.
Not doing that simply leads to very obscure errors where seemingly valid TS code throws random "undefined" errors in runtime.
What do you think?
ritical dependency: the request of a dependency is an expression
Hello!
Is it possible right now to inject multiple tagged services using constructor injection and decorators?
Example:
@Service()
class Foo {
constructor (@Inject(TaggedService) TaggedService[] services) {
}
}
Or do we need something like @InjectMany
?
Thanks.
Hi,
I'd like to inject the Server created by restify.createServer().
It should look something like this:
Container.set(restify.Server, server);
I'm providing the instance once the createServer() promise is resolved successfully.
The problem is, Server is an interface and not a class, it is not described as a class anywhere in restify's definition file.
Naturally, I'm able to access the Server instance's prototype, but it is not described via typescript anywhere.
How would you suggest I should inject it?
Even if providing the instance as follows would work (I don't know if it would):
Container.set((server as any).prototype, server);
I won't be able to do something like this in the class I'm injecting into (since here Server would be referring to an interface):
@Inject()
server: Server;
Would named services be the solution? Is there a way to do it without them?
Hi there,
After calling localhost:4001/, i get this error in my console:
C:\Applications\Node\exotica\server>node app.js
Server is up and running at port 3000
TypeError: connectionManager.has is not a function
at Object.value (C:\Applications\Node\exotica\node_modules\typeorm-typedi-extensions\decorators\OrmCustomRepository.js:13:40)
at C:\Applications\Node\exotica\node_modules\typedi\Container.js:171:32
at Array.forEach (native)
at Function.Container.applyPropertyHandlers (C:\Applications\Node\exotica\node_modules\typedi\Container.js:162:23)
at Function.Container.get (C:\Applications\Node\exotica\node_modules\typedi\Container.js:68:14)
at C:\Applications\Node\exotica\node_modules\typedi\Container.js:148:34
at Array.map (native)
at Function.Container.initializeParams (C:\Applications\Node\exotica\node_modules\typedi\Container.js:143:27)
at Function.Container.get (C:\Applications\Node\exotica\node_modules\typedi\Container.js:48:48)
at Object.getFromContainer (C:\Applications\Node\exotica\node_modules\routing-controllers\container.js:36:42)
From: typestack/routing-controllers#116 (comment)
pleerock: But I think we can resolve this issue and move reflect-metadata read from @service decorator in some other place in the Container and check if it will work this way.
slavafomin: Considering moving reflection to the service layer — I think it's the best way to go. We will have centralized place where container is configured and decorators could be very thin, so their functionality could easily be replicated in other "aggregating" decorators of sort. And the DI could be configured without using any decorators at all, which is good for classes coming from third-party libraries where you can't add decorators.
If a service is registered with the global container instance using a token, a ServiceNotFound error is thrown when calling scopedContainer.get(ServiceToken)
.
import {Container, Service, Token} from "typedi";
interface FooService {
marco(): void;
}
const FooServiceToken = new Token<FooService>();
// @Service({ id: FooServiceToken, factory: () => new FooServiceI() }) <= Providing a factory does not work either
@Service(FooServiceToken)
class FooServiceI implements FooService {
public marco() {
console.log("polo");
}
}
Container.get(FooServiceToken).marco(); // Works
const scopedContainer = Container.of({});
scopedContainer.get(FooServiceI).marco(); // Works
scopedContainer.get(FooServiceToken).marco(); // throws ServiceNotFoundError
an instance can be retrieved from the scoped container if the type of the desired implementation is passed, but not the token under which the service for that type was registered.
Using typedi version 0.6.0
Like Spring @PostConstruct
, define a method which invoked after the object has been created and injected. So, we can do some init like a constructor.
Another issue, I've found when migrating from Angular Injector is that there is no way to register service using interface as a type.
The problem is that interfaces are design-time only artifacts, which are deleted from compiled code altogether. So there is no way to reference the service by it's interface name at runtime.
Angular approached this problem by providing a special class called InjectionToken
. The workflow is the following: first, you create an instance of the injection token: export const DI_SEQUELIZE = new InjectionToken<Sequelize>('sequelize');
, then you use it to register service with the container. By using such hint, typescript can correctly track types of the instances returned from the container.
Right now, if I register a named service and then get it, the return type is not inferred, so I have to manually cast it to a correct type, which makes code harder to read and maintain.
@pleerock What could be done about this?
Hei, i'm experiencing weird behaviour in my tests with constructor injects
//..
import {Container} from 'typedi';
import {AccessTokenService} from 'src/authentication/services/access-token-service';
import * as cfg from 'src/application/config';
Container.set('cfg.auth.jwt',cfg.auth.jwt);
const accessTokenService = Container.get(AccessTokenService);
accessTokenService.makeAccessToken(user);
//..
Dependecies are undefined when i configure them in the constructor
import {Service, Inject, Require} from 'typedi';
// ..
@Service('AccessTokenService')
export class AccessTokenService {
constructor(
@Require('moment') private moment,
@Require('jsonwebtoken') private jsonwebtoken,
@Inject('cfg.auth.jwt') private jwt
) {}
makeAccessToken(user: User) {
console.log(typeof this.jsonwebtoken); //undefined
console.log(typeof this.jwt); //undefined
console.log(typeof this.moment); //undefined
// ...
}
}
But this works
import {Service, Inject, Require} from 'typedi';
// ..
@Service('AccessTokenService')
export class AccessTokenService {
@Require('moment') private moment;
@Require('jsonwebtoken') private jsonwebtoken;
@Inject('cfg.auth.jwt') private jwt;
makeAccessToken(user: User) {
console.log(typeof this.jsonwebtoken); //object
console.log(typeof this.jwt); //object
console.log(typeof this.moment); //function
// ...
}
}
Container.set({
"koa-app": app,
"koa-server": server
});
same as Container.set("koa-app", app)
and Container.set("koa-server", server)
npm install bcryptjs --save
npm install @types/bcryptjs --save
I'd like to expose the bcryptjs utility as a service. Is this possible? Right now i'm using:
import * as bcrypt from 'bcryptjs'
... in my controller, but this doesn't feel "right". The same for other external libraries.
Thanks so much.
As discussed here: #11 (comment) we need a way to clear the "dirty" container effectively removing all registered services, instances and param handlers. This will allow us to have more isolated unit tests.
I use TypeDI
to integrate routing-controllers
(express
) and TypeORM
(with extensions).
I know how to test routes
but
How can I do a unit test with a service
or custom repository
?
I do this
@Service()
class Injector {
@OrmRepository()
userRepository: UserRepository;
}
let injector: Injector;
before(() => {
injector = Container.get(Injector);
});
but failed
EntityMetadataNotFound: No metadata for "User" was found.
it seems the TypeORM
is still under initialization when the test case wants to get object
from TypeDI
.
Hey!
Is there a way to check if container has an instance of the specific type w/o actually creating this instance?
E.g: if (Container.has(CarService)) {}
.
Thanks )
0|Browser- | TypeError: Cannot read property 'bind' of undefined
0|Browser- | at Function.Container.get
Removing dependency removes error.
Using like this:
const playerService = Container.get(PlayerService);
Does not help. Gives the same error.
Using at runtime gives the same error. (the funny thing, even not calling method directly but just writing Container.get there)
There are no circular dependencies between services.
Full error log:
0|Browser- | TypeError: Cannot read property 'bind' of undefined
0|Browser- | at Function.Container.get (~/node_modules/typedi/Container.js:64:39)
0|Browser- | at Object.getValue (~/node_modules/typedi/decorators.js:31:70)
0|Browser- | at ~/node_modules/typedi/Container.js:110:40
0|Browser- | at Array.forEach (native)
0|Browser- | at Function.Container.applyPropertyHandlers (~/node_modules/typedi/Container.js:105:14)
0|Browser- | at Function.Container.get (~/node_modules/typedi/Container.js:66:14)
0|Browser- | at Object.getValue (~/node_modules/typedi/decorators.js:31:70)
0|Browser- | at ~/node_modules/typedi/Container.js:110:40
0|Browser- | at Array.forEach (native)
0|Browser- | at Function.Container.applyPropertyHandlers (~/node_modules/typedi/Container.js:105:14)
This is in current master
branch (6876e60):
Based on example 13, the following code:
import "reflect-metadata";
import { Container, Service, Token } from "../../src/decorators/Service";
@Service()
export class QuestionRepository {
userName: string;
save() {
console.log(`saving question. author is ${this.userName}`);
}
}
export const QuestionController = new Token<QuestionControllerImpl>("QCImpl");
@Service({ id: QuestionController })
export class QuestionControllerImpl {
constructor(protected questionRepository: QuestionRepository) {
}
save(name: string) {
if (name)
this.questionRepository.userName = name;
this.questionRepository.save();
}
}
const request1 = { param: "Timber" };
const controller1 = Container.of(request1).get(QuestionController);
controller1.save("Timber");
Container.reset(request1);
// Container.removeFromRequest(request1, QuestionController);
const request2 = { param: "Guest" };
const controller2 = Container.of(request2).get(QuestionController);
controller2.save("");
Container.reset(request2);
console.log("Equivalent controllers", controller1 === controller2);
console.log("Equivalent to global", controller1 === Container.get(QuestionController));
The above code produces the following output:
$ ./node_modules/.bin/ts-node sample/sample13-multiple-containers/app.ts
saving question. author is Timber
saving question. author is Timber
Equivalent controllers true
Equivalent to global true
Expected output:
$ ./node_modules/.bin/ts-node sample/sample13-multiple-containers/app.ts [0]-[1s/1541]┘
saving question. author is Timber
saving question. author is undefined
Equivalent controllers false
Equivalent to global false
I'm having an issue where Container.getMany(TOKEN)
is returning an empty array, despite having {id: TOKEN, multiple: true}
services in my project.
I have also tried with @InjectMany(TOKEN)
to no avail.
Example repo with reproduction: https://github.com/j3ddesign/typedi-getMany-example
EDIT: as a sanity check I also replicated the example at https://github.com/typestack/typedi#using-service-groups - This also failed to get the services.
I've tried looking through the source code of typedi to see if I can PR this, but currently it's a bit over my head. Would love a fix, this is a great feature
Is @Service
always required for constructor injection like:
@Service() // <===== this
class CoffeeMaker {
private beanFactory: BeanFactory;
private sugarFactory: SugarFactory;
private waterFactory: WaterFactory;
constructor(beanFactory: BeanFactory, sugarFactory: SugarFactory, waterFactory: WaterFactory) {
this.beanFactory = beanFactory;
this.sugarFactory = sugarFactory;
this.waterFactory = waterFactory;
}
}
let coffeeMaker = Container.get<CoffeeMaker>(CoffeeMaker);
coffeeMaker.make();
seems odd, but maybe you need it for something under the hood?
I've code:
@Service()
class Car {
public serial = Math.random();
}
console.log(
Container.of({}).get(Car).serial === Container.of({}).get(Car).serial,
); // false given
But I expect true.
I know, there is global service option, but I don't want to have one instance across all containers. I want to have one instance per every scoped container.
hey, another weird issue:
// services.ts
import {Token, Service, Inject} from 'typedi'
export declare interface IFoo {
foo(): void
}
const FooImpl = new Token<IFoo>()
@Service(FooImpl)
export class Foo implements IFoo {
foo (): string {
return 'foo'
}
}
@Service('bar')
export class Bar {
@Inject(FooImpl.name)
public foo: Foo
}
use case 1.
//main.ts
import 'reflect-metadata'
import {Container} from 'typedi'
console.log(Container.services) //made it public for testing
-> nothing inside services
use case 2.
//main.ts
import 'reflect-metadata'
import {Container} from 'typedi'
import {Foo, Bar} from './services'
console.log(Container.services) //made it public for testing
-> nothing inside services
use case 3.
//main.ts
import 'reflect-metadata'
import {Container} from 'typedi'
require('./services')
console.log(Container.services) //made it public for testing
-> all services from services.ts
are available in container
personally i would prefer 1. but that seems to be unpossible i think
2. should work, i dunno why, maybe tsc optimizes the unused import away?!
3. is okish, but should be documented i think
Hello!
I have a project in which I use typedi
through npm
. The npm-package includes source-map files for all .js
files. However, those source maps reference original files like this: ../../src/Container.ts
, so this path leads outside of node_modules
directory and points to non-existent source files.
I'm using source-map-support
module to make stack traces more readable, but the source maps of typedi
make reported paths weird. It tries to resolve them to files in my project. This complicates debugging.
Actually, I would love those stack traces to be resolved back to original TypeScript files, but sadly the npm-package doesn't contain source files at all. If source files were present it would allow to much easier trace and resolve errors in projects and even to use debugger to dive into internals of typedi
when used with the real project (this really helps with integration).
So, I think there could be two courses of action:
1). Add source .ts
files to the npm-package.
2). Remove source maps from npm package because they point to inexistent files.
Does it makes sense?
Thank you.
Hello,
maybe I am getting something wrong, but I am looking for a way to provide a parameter to the constructor. My use case is, that I would like to inject a logger, that should be instantiated with a module name, e.g. const logger = new Logger('moduleX');
That I would like to change to work like this
class ModuleX {
@Inject
private logger: Logger;
public doSmth () {
this.logger.info('log something');
}
}
Obviously this is not supported and therefor I assume not a good practice, or am I missing something?
thank you!
Hi.
I have a simple test project and it perfectly works in all browsers except IE11.
What do I need to do to be able to use 'typedi' in IE11? Is it possible?
I already tried to include es6-shim but it doesn't help.
Right now code is looks like this:
import "reflect-metadata";
import {Container, Service} from "typedi";
import Some from "./some";
@Service()
export default class TestClass {
constructor(private some: Some, private some2: Some){
}
test1() {
this.some.someMethod();
this.some2.someMethod();
}
}
Container.get<TestClass>(TestClass).test1();
And only in IE11 I have 'undefined' for both 'some' and 'some2' in TestClass constructor.
Thanks.
I really dig this library, but I'm missing named params from Javascript land (I still consider myself only at like 45% with Typescript).
If I have a service such as:
@Service()
export class WebhookService {
constructor(
@OrmRepository() private borrowerRepository: BorrowerRepository,
@OrmRepository() private webhookRepository: WebhookRepository,
private client: ClientService,
@Logger(__filename) private log: ILogger
) { }
My tests for this become clunky for instantiating:
const service = new WebhookService(borrowerRepoMock, webhookRepoMock, clientServiceMock, logMock);
It would be nice if I could use named params so order wouldn't matter:
const service = new WebhookService({
borrowerRepo: borrowerRepoMock,
webhookRepo: webhookRepoMock,
clientService: clientServiceMock,
log: logMock
});
Do you have any sample patterns to achieve this cleanly while still maintaining the dependency injected behavior?
It would be nice if one could do something like this:
import { Container } from 'typedi/Container';
import { IRecordRepository } from '../repository/IRecordRepository';
import { RecordRepository } from '../repository/neo4j/RecordRepository';
Container.provide([
{ name: 'RecordRepository', type: IRecordRepository, value: new RecordRepository() }
]);
then later do:
@Controller('/app/:appId/record')
export default class RecordController {
@Inject()
recRepository: IRecordRepository;
}
notice how I pointed it using interfaces vs a naming technique. Is this possible?
For now it's not possible to use Token as service id in combination with factory, like this:
interface SomeInterface {
foo();
}
const SomeInterfaceToken = new Token<SomeInterface>();
@Service()
class SomeInterfaceFactory {
create() {
return new SomeImplementation();
}
}
@Service({ id: SomeInterfaceToken, factory: [SomeInterfaceFactory, 'create']})
class SomeImplementation implements SomeInterface {}
ServiceOptions, that i suppose, used in background typedi require id as string.
class SomeService {
@Inject(ConfigService) config: Config
cache = new SomeCache(config.cacheConfig)
}
config
is injected after constructor and this will result in undefined
error
Provide a method to do some initialization after dependency injected. For example:
class SomeService {
@Inject(ConfigService) config: Config
@AfterInit
init() {
this.cache = new SomeCache(config.cacheConfig)
}
}
From @Service
JSdoc:
Marks class as a service that can be injected using container.
So it works like in Angular Injector and Inversify, so maybe it would be better to rename it to @Injectable
like in this two DI?
@Service
could be deprecated and exported as an alias for @Injectable
for now.
Is it possible to not use a global container and use isolated private containers? So like this:
let myContainer = new Container();
myContainer.set(....)
let coffeeMaker = myContainer.get<CoffeeMaker>(CoffeeMaker);
most of the other libraries I see do this, like:
I have code similar to the following:
export interface TestService {
sayHello(): void;
}
export const TestService = new Token<TestService>("TestService");
@Service({ id: TestService, factory: () => new TestServiceImpl() })
class TestServiceImpl {
public sayHello() {
console.log("Hello world!");
}
}
Then I can't run the following:
Container.get(TestService).sayHello();
// Works.
Container.of({ foo: "bar" }).get(TestService).sayHello();
// ServiceNotFoundError: Service "TestService" was not found, looks like it was not registered in the container. Register it by calling Container.set before using service.
An explicit set in the scoped container fixes the issue but also duplicates the service definition.
пишу так
///<reference path="Render.ts" />
import {Container} from "typedi";
class SomeClass {
someMethod() {
console.log('test1');
}
}
let someClass = Container.get(SomeClass);
someClass.someMethod();`
Компилирую в phpstorm
на выходе
var Template;
(function (Template) {
var Render = (function () {
function Render() {
}
Render.prototype.test = function () {
};
return Render;
}());
Template.Render = Render;
})(Template || (Template = {}));
//# sourceMappingURL=Main.js.map
Получилось что скомпилился только мой файл
packege.json
"build-js": "browserify src/Main.js > main.js | browserify node_modules/typedi/index.js > typeid.js",
Подключал так
<script type="text/javascript" src="typeid.js"></script>
<script type="text/javascript" src="main.js"></script>
Angular DI offers several options for providing dependencies to the container:
[
{ provide: ..., useClass: FakeLogger },
{ provide: ..., useExisting: Logger},
{ provide: ..., useValue: { log: () => {} } },
{ provide: ..., useFactory: createLogger }
]
In particular, it would be great if we could provide a factory
function. I think this would be much better than the existing solution that requires you use @Service({ factory: ... })
. With the factory defined in the service decorator it's much more difficult to mock out in tests.
Container.provide([
{ name: 'foo', value: new Foo() },
{ name: 'foo.class', class: Foo },
{ name: 'foo.factory', factory: () => new Foo() },
])
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.