#Is there a way to enforce Injection Token uniqueness in an app?

11 messages · Page 1 of 1 (latest)

trim solstice
#

#dependencyinjection #inject #singleton

I asked this on SO here: https://stackoverflow.com/questions/77783597/in-nestjs-can-i-prevent-multiple-providers-with-the-same-injection-token but my friend suggested this discord too.

Basically I want to ensure that in my app I don't accidentally have both the development and production version of a service provider in my DI-tree. Right now if I write:

@Module({
  providers: [
    {
      provide: 'MyService',
      useClass: ProdMyService,
    }
  ],
  exports: ['MyService'],
})
export class ProdModule { }

@Module({
  providers: [
    {
      provide: 'MyService',
      useClass: DevMyService,
    }
  ],
  exports: ['MyService'],
})
export class DevModule { }

@Module({
  controllers: [MyController],
  imports: [ProdModule, DevModule],
})
export class AppModule { }

class MyController {
  constructor(@Inject('MyService') private readonly service: MyServiceInterface) { }
}

it seems like chance which MyService version will get used. I would prefer the app alert me about this as an error.

wary sigil
#

Probably not the answer you would like but ditch the dev and prod modules. Just inject the dependency based on your environment, meaning you only need 1 module. Also, symbols are unqiue

trim solstice
#

thanks. i'm open to suggestions for sure ... how do you mean doing this though? i had considered:

@Module({
  providers: [{
    provide: 'MyService',
    useFactory: () => isProd ? new ProdMyService() : new DevMyService(),
  }],
wary sigil
trim solstice
#

this does seem like better than two modules, but i guess i'm also worried that as the number of modules / teams writing code goes up, it becomes hard to ensure that an injection token is not used to provide two different things.

wary sigil
#

perhaps someone else has a different take on it

#

I personally havent had this issue and I have written a couple SaaS products at my previous job*

trim solstice
#

thanks. yea Symbol is a good suggestion too. i have a big map of strings so that's not really my biggest worry.

drifting ice
#

My favourite way of writing injection tokens for things that can have multiple implementations is to use an
abstract class that both that all of the implementations extend. Then, you can use the abstract class as the injection token and don't need to bother with matching tokens to types.

trim solstice