Angular 21 de Cero a Experto / Servicios y DI
Tokens de inyección: inyectar lo que no es una clase
Hasta ahora inyectabas clases: inject(BolsilloStore). Pero a veces necesitas inyectar algo
que NO es una clase: la URL base de tu API, una bandera de configuración, un valor del
entorno, una función. No puedes hacer inject("https://api..."). Para eso están los TOKENS de
inyección: llaves con nombre que registran cualquier valor en el sistema de DI. Hoy los
dominas y cierras tu comprensión completa de la inyección de dependencias.
Una llave con nombre para cualquier cosa
Crear y usar un InjectionToken
import { InjectionToken } from '@angular/core';
export interface AppConfig {
apiUrl: string;
moneda: string;
maxGastos: number;
}
// 1. crea el token (la "etiqueta única"), tipado
export const APP_CONFIG = new InjectionToken<AppConfig>('config.app');import { ApplicationConfig } from '@angular/core';
import { APP_CONFIG } from './config.tokens';
// 2. registra el VALOR del token en el arranque de la app
export const appConfig: ApplicationConfig = {
providers: [
{ provide: APP_CONFIG, useValue: {
apiUrl: 'https://api.mibolsillo.com',
moneda: 'COP',
maxGastos: 1000,
}},
],
};import { Injectable, inject } from '@angular/core';
import { APP_CONFIG } from './config.tokens';
@Injectable({ providedIn: 'root' })
export class ApiService {
// 3. inyecta el valor con el token como llave
private config = inject(APP_CONFIG);
cargarGastos() {
return fetch(`${this.config.apiUrl}/gastos`); // usa la config inyectada
}
}El patrón es siempre el mismo: crear el token (tipado), proveer su valor, inyectarlo. El
tipo <AppConfig> hace que inject(APP_CONFIG) devuelva un AppConfig con autocompletado y
verificación completa.
¿Por qué no simplemente importar una constante?
Podrías escribir export const API_URL = "https://..." y import donde la necesites. ¿Por
qué molestarse con un token?
Tokens con valor de fábrica
Un token también puede calcular su valor con una función que, a su vez, inyecta otras cosas:
export const ES_MOVIL = new InjectionToken<boolean>('es-movil', {
providedIn: 'root',
factory: () => window.matchMedia('(max-width: 767px)').matches,
});
// se inyecta igual: private esMovil = inject(ES_MOVIL);El factory corre en contexto de inyección (por eso podría usar inject() dentro), y el
providedIn: 'root' lo hace tree-shakable. Angular usa este patrón internamente para muchas
de sus configuraciones.
¿Cuándo necesitas un `InjectionToken` en lugar de inyectar una clase?
Mini-reto
Diseña la configuración de "Mi Bolsillo" con tokens: 1) crea un InjectionToken<AppConfig>
con apiUrl, moneda y alertaSaldoBajo (un número); 2) escribe el provider que le da
valor en el arranque; 3) inyéctalo en un BolsilloStore y úsalo para decidir si el saldo
está "bajo". Luego explica cómo lo sustituirías en un test para probar la alerta sin depender
de la config real.
Qué sigue
Cierras la teoría de servicios y DI: sabes crear servicios, inyectarlos con inject(),
controlar su alcance con la jerarquía, exponerlos como stores de señales e inyectar valores
con tokens. Es hora del reto del módulo: construir el BolsilloStore completo —el store
reactivo que será el cerebro de tu app durante todo el curso— y probarlo en vivo.