tsyringe icon indicating copy to clipboard operation
tsyringe copied to clipboard

Custom constructor properties

Open shadrech opened this issue 4 years ago • 14 comments

Is there a way we can add a custom argument to a class constructor? e.g

@injectable()
class ExampleClass {}

@injectable()
class MyClass {
  constructor(custom: CustomInterface, example: ExampleClass) {}
}

const instance = container.resolve(MyClass, { custom }); // not possible now but to illustrate my point 

I need to provide a different custom object to the class on each instantiation. Basically this stackoverflow comment describes perfectly what I mean (quite surprised the library hasn't got this ability already tbh!)

shadrech avatar Apr 29 '20 13:04 shadrech

Ok I guess you could do something like

const custom: CustomInterface = {};
container.registerInstance("CustomInterface", { useValue: custom });
const instance = container.resolve(MyClass);

// to clear up instances you've registered with registerInstance()
container.clearInstances();

Would be nice if this was in the docs. Right now I don't see registerInstance() mentioned anywhere in the docs (except for when speaking of clearInstances(). I think adding it to docs and mentioning that this is how one can supply different parameters to constructors for each instances. I don't mind submitting a PR for these doc additions? @Xapphire13

shadrech avatar May 01 '20 17:05 shadrech

Also is the latest commit to master (which adds .clearInstance() to DependencyContainer typings) published. Even though its in source code in github when I pull in tsyringe from npm (latest which is v4.1.0) its not appearing in dist typings folder

shadrech avatar May 01 '20 17:05 shadrech

Hey! Thanks for the issue, I'll look into it in the next few weeks =].

You're right, I haven't gotten around to publishing the new version yet. I'm aiming on doing that this upcoming week.

Xapphire13 avatar May 02 '20 21:05 Xapphire13

I just released v4.2.0 =]

Xapphire13 avatar May 05 '20 23:05 Xapphire13

Thanks man @Xapphire13. So to clarify, to provide a different custom object to the class on each instantiation the recommended tsyringe way is to do o=something like

@injectable()
class ExampleClass {}

@injectable()
class MyClass {
  constructor(@inject('custom') custom: string, example: ExampleClass) {}
}

const name: string = 'Hello world';
container.registerInstance("custom", name);
const instance = container.resolve(MyClass);
container.clearInstances();

If resolving a new MyClass with a new custom param is it necessary to call .clearInstances() before registering the new custom instance again?

shadrech avatar May 06 '20 09:05 shadrech

@Xapphire13 Is there not a better way to pass custom parameters rather than registerInstance? I would think something like

const instance = container.resolve(MyClass, { custom: 'Hello world' });

where u pass the custom param as a second argument to resolve would be much better? Surely this is fundamental oop design?

shadrech avatar Jul 22 '20 10:07 shadrech

I guess this already works with @autoinjectable?

it("autoinjectable works with additional 'unmanaged' parameters", () => {
  @singleton()
  class Foo {}

  @autoInjectable()
  class Bar {
    constructor(public custom: any, public foo?: Foo) {}
  }

  // const bar = container.resolve(Bar);
  const bar = new Bar({ x: 5 });
  expect(bar.foo).toBeDefined();
  expect(bar.custom.x).toBe(5);
});```

Obiwarn avatar Jul 30 '20 11:07 Obiwarn

I think inversifyJS uses the @unmanageddecorator for this. Something like that would help a lot (e.g. for optional unmanaged parameters in the constructor).

Obiwarn avatar Jul 30 '20 11:07 Obiwarn

@autoinjectable would not work with child containers.

As a workaround, you can register a "factory" class and use that to create specific instances, ex:

const factory = container.resolve(MyClassFactory); // not possible now but to illustrate my point 
const instance = factory.create(custom);

But you need to build manually such a factory and it is a bit of a workaround. The ability to pass unmanaged parameters to resolve would be nice. I would use that. 👍

ibratoev avatar Mar 27 '21 11:03 ibratoev

That's an interesting idea - it's possible (probably) to change the resolve() API to be resolve(token, ...args) or something like that. Sort of like autoInjectable. I'd definitely look at a PR for this.

MeltingMosaic avatar Mar 29 '21 21:03 MeltingMosaic

Just started using tsyringe and find the need for container.resolve(MyClass, ...args) also. Thanks for this library and I hoping someone creates a PR.

@injectable()
class ExampleClass {}

@injectable()
class MyClass {
  constructor(public example: ExampleClass, custom?: CustomInterface) {}
}

const instance1 = container.resolve(MyClass, { custom }); 

const instance2 = container.resolve(MyClass); 

codeBelt avatar Apr 05 '22 02:04 codeBelt

Any updates to this?

fr3fou avatar Nov 01 '22 14:11 fr3fou

Any update on this?

danielvouch avatar Jul 31 '23 15:07 danielvouch

Any updates for this?

samuelthng avatar Dec 02 '23 06:12 samuelthng