Inyección con inject()
Angular introdujo la función inject() como una alternativa moderna y más flexible a la inyección de dependencias por constructor. Esta función permite obtener instancias de servicios de manera funcional dentro de componentes, servicios y otros elementos del framework.
La función inject() se importa desde @angular/core
y se puede utilizar durante la fase de construcción del contexto de inyección, lo que incluye constructores, inicializadores de propiedades, y funciones que se ejecutan durante la creación del componente.
Sintaxis básica
Para utilizar la función inject(), simplemente la llamamos pasando el token del servicio que deseamos inyectar:
import { Component, inject } from '@angular/core';
import { UserService } from './user.service';
@Component({
selector: 'app-profile',
template: `
<h2>{{ user.name }}</h2>
<p>{{ user.email }}</p>
`
})
export class ProfileComponent {
private userService = inject(UserService);
user = this.userService.getCurrentUser();
}
Inyección en inicializadores de propiedades
Una de las ventajas principales de inject() es que permite la inyección directamente en inicializadores de propiedades, haciendo el código más conciso y legible:
import { Component, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { NotificationService } from './notification.service';
@Component({
selector: 'app-data',
template: `
@for (item of data; track item.id) {
<div>{{ item.name }}</div>
}
`
})
export class DataComponent {
private http = inject(HttpClient);
private notifications = inject(NotificationService);
data = this.http.get<any[]>('/api/data');
showMessage(message: string) {
this.notifications.show(message);
}
}
Inyección en funciones auxiliares
La función inject() también permite crear funciones auxiliares reutilizables que encapsulan lógica de inyección. Esto es especialmente útil para patrones comunes:
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './auth.service';
// Función auxiliar reutilizable
function createAuthGuard() {
const auth = inject(AuthService);
const router = inject(Router);
return () => {
if (auth.isAuthenticated()) {
return true;
}
router.navigate(['/login']);
return false;
};
}
@Component({
selector: 'app-dashboard',
template: `<h1>Panel de control</h1>`
})
export class DashboardComponent {
private authGuard = createAuthGuard();
ngOnInit() {
this.authGuard();
}
}
Inyección con opciones
Al igual que la inyección por constructor, inject() soporta opciones avanzadas para controlar el comportamiento de la inyección:
import { Component, inject } from '@angular/core';
import { ConfigService } from './config.service';
@Component({
selector: 'app-settings',
template: `
@if (config) {
<div>{{ config.appName }}</div>
} @else {
<div>Configuración no disponible</div>
}
`
})
export class SettingsComponent {
// Inyección opcional - no falla si el servicio no está disponible
private config = inject(ConfigService, { optional: true });
// Inyección con self - solo busca en el inyector del componente actual
private localService = inject(LocalService, { self: true });
}
Casos de uso típicos
La función inject() es especialmente útil en los siguientes escenarios:
1 - Componentes con múltiples dependencias:
@Component({
selector: 'app-complex',
template: `<!-- template content -->`
})
export class ComplexComponent {
private router = inject(Router);
private route = inject(ActivatedRoute);
private http = inject(HttpClient);
private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar);
// Lógica del componente más limpia sin constructor largo
}
2 - Inicialización condicional:
@Component({
selector: 'app-conditional',
template: `<!-- template -->`
})
export class ConditionalComponent {
private analytics = inject(AnalyticsService, { optional: true });
trackEvent(event: string) {
// Solo trackea si el servicio está disponible
this.analytics?.track(event);
}
}
La función inject() representa una evolución natural en el sistema de inyección de dependencias de Angular, ofreciendo mayor flexibilidad y un código más expresivo mientras mantiene toda la robustez del sistema de DI tradicional.
Diferencias constructor vs inject()
Angular ofrece dos enfoques principales para la inyección de dependencias: el método tradicional por constructor y la función moderna inject(). Cada uno tiene sus características específicas y casos de uso apropiados.
Enfoque tradicional por constructor
La inyección por constructor ha sido el método estándar desde las primeras versiones de Angular. Los servicios se declaran como parámetros del constructor y se asignan automáticamente a propiedades de la clase:
import { Component } from '@angular/core';
import { UserService } from './user.service';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-traditional',
template: `<p>{{ user.name }}</p>`
})
export class TraditionalComponent {
constructor(
private userService: UserService,
private http: HttpClient
) {}
loadUser() {
return this.userService.getCurrentUser();
}
}
Diferencias fundamentales
Ubicación de la inyección:
- Constructor: Las dependencias se declaran como parámetros y están disponibles después de
super()
- inject(): Las dependencias se pueden obtener en inicializadores de propiedades y métodos
Sintaxis y verbosidad:
- Constructor: Requiere declarar parámetros y asignarlos a propiedades
- inject(): Permite inyección directa en una sola línea
// Constructor - más verboso
class ComponentWithConstructor {
constructor(
private userService: UserService,
private router: Router,
private dialog: MatDialog
) {}
}
// inject() - más conciso
class ComponentWithInject {
private userService = inject(UserService);
private router = inject(Router);
private dialog = inject(MatDialog);
}
Flexibilidad en el momento de inyección
La función inject() ofrece mayor flexibilidad sobre cuándo y cómo se obtienen las dependencias:
@Component({
selector: 'app-flexible',
template: `<!-- template -->`
})
export class FlexibleComponent {
// Inyección condicional
private analytics = this.isProduction()
? inject(AnalyticsService)
: inject(MockAnalyticsService);
// Inyección en propiedades computadas
private config = inject(ConfigService);
private apiUrl = this.config.getApiUrl();
private isProduction(): boolean {
return inject(EnvironmentService).isProd();
}
}
Herencia y clases base
Constructor requiere llamar a super()
en clases derivadas, mientras que inject() funciona de forma independiente:
// Con constructor
abstract class BaseComponent {
constructor(
protected logger: LoggerService,
protected router: Router
) {}
}
class DerivedComponent extends BaseComponent {
constructor(
logger: LoggerService,
router: Router,
private userService: UserService // Nueva dependencia
) {
super(logger, router); // Obligatorio
}
}
// Con inject() - más simple
abstract class BaseComponentInject {
protected logger = inject(LoggerService);
protected router = inject(Router);
}
class DerivedComponentInject extends BaseComponentInject {
private userService = inject(UserService); // Sin super() necesario
}
Compatibilidad con funciones
La función inject() permite crear funciones auxiliares que encapsulen lógica de inyección, algo imposible con constructores:
// Función auxiliar reutilizable
function createNotificationHandler() {
const notifications = inject(NotificationService);
const logger = inject(LoggerService);
return (message: string, type: 'success' | 'error') => {
notifications.show(message, type);
logger.log(`Notification: ${message}`);
};
}
@Component({
selector: 'app-reusable',
template: `<button (click)="showSuccess()">Mostrar éxito</button>`
})
export class ReusableComponent {
private notify = createNotificationHandler();
showSuccess() {
this.notify('Operación completada', 'success');
}
}
Cuándo usar cada enfoque
Usar constructor cuando:
- Trabajas con equipos que prefieren el patrón tradicional
- Necesitas compatibilidad con versiones anteriores de Angular
- Las dependencias son obligatorias y se usan en el constructor
- Prefieres la explicitación de dependencias en la firma del constructor
Usar inject() cuando:
- Quieres código más conciso y legible
- Necesitas inyección condicional o dinámica
- Trabajas con herencia compleja de componentes
- Creas funciones auxiliares que requieren servicios
- Usas las características modernas de Angular
Migración gradual
Ambos enfoques pueden coexistir en el mismo componente, permitiendo migración gradual:
@Component({
selector: 'app-hybrid',
template: `<!-- template -->`
})
export class HybridComponent {
// Constructor para servicios críticos
constructor(
private coreService: CoreService
) {}
// inject() para servicios opcionales o auxiliares
private analytics = inject(AnalyticsService, { optional: true });
private logger = inject(LoggerService);
performAction() {
this.coreService.execute();
this.analytics?.track('action_performed');
this.logger.info('Action completed');
}
}
La elección entre constructor e inject() depende del contexto específico del proyecto, las preferencias del equipo y los requisitos de funcionalidad. Ambos enfoques son válidos y mantienen la robustez del sistema de inyección de dependencias de Angular.

Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Angular es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Angular
Explora más contenido relacionado con Angular y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender el uso básico de la función inject() para obtener servicios en Angular.
- Identificar las ventajas de inject() frente a la inyección por constructor.
- Aprender a usar inject() en inicializadores de propiedades y funciones auxiliares.
- Conocer las opciones avanzadas de inyección con inject(), como inyección opcional y self.
- Saber cuándo usar inject() o el constructor según el contexto y necesidades del proyecto.