InjectionToken is Angular’s way of creating a unique, type-safe key for non-class dependencies. It ensures that Angular knows exactly what you’re injecting, even if it’s a plain object or a configuration interface. This helps you overcome the fragility of strings which improves clarity across your codebase.

The Problem with String-Based Providers

If you’re using strings as keys to inject configurations, you’re setting yourself up for maintenance nightmares. One typo, and things silently break. That approach also makes it harder for TypeScript to validate anything at compile time.

Meet InjectionToken: A Smarter Way to Inject Config

InjectionToken is Angular’s way of creating a unique, type-safe key for non-class dependencies. It ensures that Angular knows exactly what you’re injecting, even if it’s a plain object or a configuration interface. This helps you overcome the fragility of strings which improves clarity across your codebase.

How It Works in Practice

Let’s say you want to inject an API configuration across multiple services. Instead of manually passing objects or importing shared constants, you define a typed token at one place, and Angular handles the rest via its DI system. Once set up, any service can inject this configuration using that token, without worrying about types or typos.

 Practical Example (Type-safe API configuration):

Step 1: Create the Token

// api-config.token.ts
import { InjectionToken } from '@angular/core';
export interface ApiConfig { baseUrl: string; apiKey: string;
}
export const API_CONFIG = new InjectionToken<ApiConfig>('api.config', { providedIn: 'root', factory: () => ({	// Default or environment-based configuration	baseUrl: 'https://api.default.com',	apiKey: 'default_key' })
});

Step 2: Inject Config into a Service

Now, a service can inject this configuration in a type-safe way:

// data.service.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { API_CONFIG, ApiConfig } from './api-config.token';
@Injectable({ providedIn: 'root' })
export class DataService { private http = inject(HttpClient); private config = inject(API_CONFIG); getData() {	return this.http.get(`${this.config.baseUrl}/items`, {	headers: { 'X-API-KEY': this.config.apiKey }	}); }
}

This approach is superior to string providers because it’s not prone to typos and is fully supported by TypeScript’s type checking.

Why This Approach Is Better

  • Type-safe: Interfaces enforce structure and reduce runtime surprises.
  • Tree-shakable: Unused config tokens won’t end up in your final bundle.
  • Refactor-friendly: No hard-coded strings or keys to update manually.
  • Globally injectable: Your config is available app-wide without tight coupling.

Final Thoughts

If you’re building scalable Angular apps, stop passing around config like it’s 2016. InjectionToken gives you a smarter, safer way to inject non-class dependencies. It’s lean, reliable, and just makes sense, especially for config. And if you’re short on time or want to avoid wiring everything yourself, consider hiring Angular developers who already know how to use InjectionToken and other best practices to build apps that scale cleanly. Let your config work for you and not against you.