mscharley / inversify-token

Token-based injection for InversifyJS
MIT License
12 stars 3 forks source link

getToken by name #245

Closed xenoterracide closed 1 year ago

xenoterracide commented 2 years ago

since an interface/token is good when you have multiple implementations, is there any way I can qualify

getToken(container, MyInterface)

by name? like @named(...)

mscharley commented 2 years ago

Hi,

I haven't really needed to use @named before, do you have a more complete example of what you're looking for? I think the answer is probably "not yet" though.

xenoterracide commented 2 years ago
export type Axios = TokenType<typeof Axios>
export type AxiosProvider = interfaces.Provider<Axios>
export const Axios = new Token<AxiosInstance>(Symbol.for('Axios'))
export const AxiosProvider = new Token<AxiosInstance>(Symbol.for('Provider<Axios>'))

const tokenContainerModule = new TokenContainerModule(bind => {
  // Constant REST Clients
  bind(Axios)
    .toConstantValue(
      withTracingInterceptor(
        axios.create({
          baseURL: env.SSO_BASE_URL,
        }),
      ),
    )
    .whenTargetNamed(ssoClient)

  bind(Axios)
    .toConstantValue(
      axios.create({
        headers: {
          accept: 'application/json',
          'content-type': 'application/x-www-form-urlencoded',
        },
        httpsAgent: new Agent({
          ca: Boolean(env.DEVEX_USE_SYSTEM_CA) ?? false ? getCA() : undefined,
        }),
      }),
    )
    .whenTargetNamed(devExchangAxiosClient)

  bind(AxiosProvider).toProvider(serviceNowAxiosProvider).whenTargetNamed(serviceNowAxiosProviderName)
})

const container = new Container()

container.load(buildProviderModule(), tokenContainerModule)

honestly I figured out how to do it reading your code

  const client = container.getNamed<Axios>(Axios.identifier, devExchangAxiosClient)
mscharley commented 2 years ago

That will definitely do the trick, and since you're using TokenType it will be stable, even if you change the type that the token provides. Using token.identifier is an escape hatch that should be functional in all cases, but it's not quite as nice or type safe as what you could get if I provided an actual getTokenNamed() though.

xenoterracide commented 2 years ago

what you're really trying to achieve here is basically aurelia 2's createInterface (I added more functionality to it) https://github.com/aurelia/aurelia/blob/master/packages/kernel/src/di.ts#L212 unfortunately, of course, that API requires this to be integrated into inversify core.

might be good to add something like getTokenBy(container, Axios).named('axios') so it's extensible...

xenoterracide commented 2 years ago

and for the default behavior it could be done as getTokenBy(container, Axios).() maybe

mscharley commented 1 year ago

Just looking back into this finally, and as far as I can tell everything is there.

import { getNamed } from "inversify-token";

const tokenContainerModule = new TokenContainerModule(bind => {
  // Constant REST Clients
  bind(Axios)
    .toConstantValue(
      withTracingInterceptor(
        axios.create({
          baseURL: env.SSO_BASE_URL,
        }),
      ),
    )
    .whenTargetNamed(ssoClient)
});

container.load(tokenContainerModule);

const ssoAxios = getNamed(tokenContainerModule, Axios, ssoClient);

class Foo {
  constructor(@injectToken(Axios) @named(ssoClient) public ssoAxios: Axios) {}
}

If I'm missing something then let me know, but for now I'm going to close this ticket.