Angular Injection Token - When to Use It?
Angular Injection Token - When to Use It?

In this post you will learn what is Angular injection token and how you can use it.

Typically inside Angular we are working a lot with injection of our services. Here I already created a UsersService.

@Injectable()
export class UsersService {
  constructor(private http: HttpClient) {}

  getUsers() {
    return this.http.get('http://localhost:3004/users');
  }
}

Let's inject it like we normally do in any application.

export class AppComponent {
  constructor(private usersService: UsersService) {
    console.log('usersService', usersService)
  }
}

And we need to register it inside our module.

@NgModule({
  ...
  providers: [UsersService]
})
export class AppModule {}

Inside browser we can see that it is available for us.

Simple inject

But the code that we wrote here is just a sugar. The provided value is actually something more. For Angular it look like this.

provides: [{provide: UsersService, useClass: UsersService}]

It works in exactly the same way as simple [UsersService] is just a sugar.

Except of useClass we have useValue, useFactory and others for different cases.

Identifiers

But it is important to understand what is provide and what is useClass. useClass is obvious as this is a class that we want to register here.

provide is not just used like a class but as a unique identifier. We could just write a string there.

provides: [{provide: 'USERS_SERVICE', useClass: UsersService}]

Here we defined a provider by this string. But it won't work like this as we must inject it differently.

export class AppComponent {
  constructor(@Inject('USERS_SERVICE') private usersService: UsersService) {
    console.log('usersService', usersService)
  }
}

Here we did it through Inject and providing the same string to find our provider. As you can see in browser it works exactly like before.

Simple inject

This is nothing more but just a unique identifier because all things that we inject must be unique for the injector.

Injecting config

And actually this @Inject plays really nicely when you need to pass a config inside. Let's create an interface for our config.

export interface UsersServiceConfigInterface {
  apiUrl: string;
}

@NgModule({
  ...
  providers: [
    ...
    {
      provide: 'USERS_SERVICE_CONFIG',
      useValue: { apiUrl: 'http://localhost:3004/users' },
    },
  ],
})

Here we created an interface and registered a config as a provider. Now at any place inside our module we can inject it.

export class AppComponent {
  constructor(
    @Inject('USERS_SERVICE') private usersService: UsersService,
    @Inject('USERS_SERVICE_CONFIG') private config: UsersServiceConfigInterface
  ) {
    console.log('usersService', usersService)
  }
}

Injection token

Which actually brings us to injection tokens inside Angular. Previously we used just string but they must be unique. But obviously strings are not really unique and we can easily to a typo and then it won't work. This is why we have injection tokens.

This is exactly what we can use as a unique identifier instead of our strings.

export const USERS_SERVICE_TOKEN = new InjectionToken<UsersService>('');
export const USERS_SERVICE_CONFIG_TOKEN = new InjectionToken<UsersServiceConfigInterface>(
  ''
);

@NgModule({
  ...
  providers: [
    {provide: USERS_SERVICE_TOKEN, useClass: UsersService},
    {
      provide: USERS_SERVICE_CONFIG_TOKEN,
      useValue: { apiUrl: 'http://localhost:3004/users' },
    },
  ],
})

Here in our module we created 2 injection tokens. Inside we specified what will be our data type. But here you must be wondering why we provided inside an empty string if it must be a unique value. This string is just a description of the token and nothing more. We can provide an empty string inside and it will still be unique.

The only thing that we need to do now is to change our string on the service to injection tokens.

export class AppComponent {
  constructor(
    @Inject(USERS_SERVICE_TOKEN) private usersService: UsersService,
    @Inject(USERS_SERVICE_CONFIG_TOKEN) private config: UsersServiceConfigInterface
  ) {
    console.log('usersService', usersService)
  }
}

And our code works like before.

So as you can see we need injection tokens in order to generate a unique identifier for our providers registration inside Angular.

And actually if you want to learn Angular with NgRx from empty folder to a fully functional production application make sure to check my Angular and NgRx - Building Real Project From Scratch course.

📚 Source code of what we've done