Inyección con inject()

Intermedio
Angular
Angular
Actualizado: 24/09/2025

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 - Autor del tutorial

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.