💻 Exemplos: Capítulo 09: Injeção de Dependências Hierárquica e Função inject()
Especialização em Front-End com Angular • Demonstrações Práticas Compiláveis
💻 Código de Exemplo 09 — Injeção de Dependências com inject() e InjectionToken Tipado
Este exemplo apresenta o modelo moderno de Injeção de Dependências (DI) do Angular 18+, utilizando a função funcional inject() (substituindo construtores verbosos com dezenas de parâmetros) e InjectionToken tipado para injeção de configurações imutáveis da aplicação.
1. Token de Configuração e Serviço: src/app/services/telemetry.service.ts
// src/app/services/telemetry.service.ts
import { Injectable, InjectionToken, inject, signal } from '@angular/core';
export interface AppConfig {
apiEndpoint: string;
enableDebugLogging: boolean;
maxRetries: number;
}
// 1. InjectionToken com factory padrão e tipagem estrita
export const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG', {
providedIn: 'root',
factory: () => ({
apiEndpoint: 'https://telemetry.empresa.com.br/v2',
enableDebugLogging: true,
maxRetries: 3
})
});
export interface TelemetryLog {
id: string;
level: 'INFO' | 'WARN' | 'ERROR';
message: string;
timestamp: string;
}
// 2. Serviço com providedIn: 'root' (Singleton por aplicação)
@Injectable({
providedIn: 'root'
})
export class TelemetryService {
// Injeção funcional limpa com inject()
private config = inject(APP_CONFIG);
logs = signal<TelemetryLog[]>([]);
recordLog(level: 'INFO' | 'WARN' | 'ERROR', message: string): void {
if (level === 'INFO' && !this.config.enableDebugLogging) return;
const entry: TelemetryLog = {
id: `log-${Date.now()}-${Math.floor(Math.random() * 1000)}`,
level,
message,
timestamp: new Date().toLocaleTimeString()
};
this.logs.update((curr) => [entry, ...curr]);
console.log(`[Telemetry Service] [${this.config.apiEndpoint}]`, entry);
}
clearLogs(): void {
this.logs.set([]);
}
}
2. Componente Consumidor: src/app/components/service-injector-demo.component.ts
// src/app/components/service-injector-demo.component.ts
import { Component, inject } from '@angular/core';
import { TelemetryService, APP_CONFIG } from '../services/telemetry.service';
@Component({
selector: 'app-service-injector-demo',
standalone: true,
template: `
<div class="max-w-xl mx-auto p-6 bg-white border border-slate-200 rounded-2xl shadow-sm space-y-6">
<div class="border-b pb-4">
<h2 class="text-xl font-bold text-slate-800">💉 Injeção de Dependências com inject()</h2>
<p class="text-xs text-slate-500">Eliminando constructors gigantescos com a API funcional</p>
</div>
<!-- Configuração Injetada via InjectionToken -->
<div class="p-4 bg-slate-50 border rounded-xl text-xs space-y-1">
<p><strong>Endpoint:</strong> <code class="font-mono text-indigo-600">{{ config.apiEndpoint }}</code></p>
<p><strong>Debug Logging:</strong> {{ config.enableDebugLogging ? 'Ativado' : 'Desativado' }}</p>
<p><strong>Retries Máximos:</strong> {{ config.maxRetries }}</p>
</div>
<!-- Botões de Ação para Disparo de Logs -->
<div class="flex gap-2">
<button
type="button"
(click)="logInfo()"
class="flex-1 py-2 bg-blue-50 text-blue-700 hover:bg-blue-100 rounded-xl text-xs font-bold transition-colors"
>
+ Log Info
</button>
<button
type="button"
(click)="logWarning()"
class="flex-1 py-2 bg-amber-50 text-amber-700 hover:bg-amber-100 rounded-xl text-xs font-bold transition-colors"
>
+ Log Warning
</button>
<button
type="button"
(click)="logError()"
class="flex-1 py-2 bg-red-50 text-red-700 hover:bg-red-100 rounded-xl text-xs font-bold transition-colors"
>
+ Log Erro
</button>
</div>
<!-- Exibição Reativa dos Logs da Store de Telemetria -->
<div class="space-y-2">
<div class="flex justify-between items-center text-xs">
<span class="font-bold text-slate-600 uppercase">Trilha de Auditoria (Signal no Serviço):</span>
<button (click)="telemetry.clearLogs()" class="text-slate-400 hover:text-slate-700 underline">
Limpar
</button>
</div>
<div class="p-3 bg-slate-900 text-slate-100 font-mono text-xs rounded-xl max-h-48 overflow-y-auto space-y-1">
@for (log of telemetry.logs(); track log.id) {
<div class="flex justify-between items-center border-b border-slate-800 pb-1">
<span>
<strong
[class.text-blue-400]="log.level === 'INFO'"
[class.text-amber-400]="log.level === 'WARN'"
[class.text-red-400]="log.level === 'ERROR'"
>
[{{ log.level }}]
</strong>
{{ log.message }}
</span>
<span class="text-slate-500 text-[10px]">{{ log.timestamp }}</span>
</div>
} @empty {
<div class="text-slate-500">// Nenhum log registrado ainda. Dispare uma ação...</div>
}
</div>
</div>
</div>
`
})
export class ServiceInjectorDemoComponent {
// Injeção de dependências sem declarar constructor!
readonly telemetry = inject(TelemetryService);
readonly config = inject(APP_CONFIG);
logInfo(): void {
this.telemetry.recordLog('INFO', 'Sessão do operador confirmada com token JWT.');
}
logWarning(): void {
this.telemetry.recordLog('WARN', 'Latência de rede no cluster sa-east-1 ultrapassou 180ms.');
}
logError(): void {
this.telemetry.recordLog('ERROR', 'Falha na conexão com réplica do banco de leitura.');
}
}
🖥️ Saída / Comportamento Esperado
Renderização Inicial:
Endpoint: https://telemetry.empresa.com.br/v2
Debug Logging: Ativado | Retries Máximos: 3
Terminal de logs: "// Nenhum log registrado ainda..."
Ao clicar em "+ Log Info":
O método telemetry.recordLog() muta o signal telemetry.logs no serviço singleton.
Linha inserida no terminal:
"[INFO] Sessão do operador confirmada com token JWT. [14:48:10]"
Console log exibe:
"[Telemetry Service] [https://telemetry.empresa.com.br/v2] { id: 'log-...', level: 'INFO', ... }"
Ao clicar em "+ Log Erro":
Linha destacada em vermelho [ERROR] é inserida no topo.
Ao recarregar o componente em outra rota, o singleton permanece íntegro e reutilizado.
🔍 Destaques da Implementação
- Adeus ao Constructor Boilerplate: A função
inject(Token)pode ser atribuída diretamente a propriedadesreadonlyde classe, facilitando herança e composição. InjectionTokencom Factory: Garante provimento de valor padrão imediato sem poluir a lista deprovidersglobais domain.ts.- Hierarquia de Injetores: O Angular resolve a injeção navegando do injetor do componente até o injetor raiz da aplicação (
root).