or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

application-management.mdchange-detection.mdcomponent-system.mddependency-injection.mdindex.mdmodern-authoring.mdresource-api.mdrxjs-interop.mdtesting.mdutilities-helpers.md
tile.json

dependency-injection.mddocs/

Dependency Injection

Angular's dependency injection system provides a powerful and flexible way to manage services and dependencies throughout an application. It supports hierarchical injection, multiple provider types, and type-safe dependency resolution.

Capabilities

Core Injection Functions

Primary functions for injecting dependencies and managing injection context.

/**
 * Inject a dependency using its token
 * @param token - The dependency token (class, InjectionToken, or string)
 * @returns The dependency instance
 */
function inject<T>(token: ProviderToken<T>): T;

/**
 * Inject a dependency with options
 * @param token - The dependency token
 * @param options - Injection options for behavior control
 * @returns The dependency instance or null if optional and not found
 */
function inject<T>(token: ProviderToken<T>, options: InjectOptions): T | null;

/**
 * Options for controlling injection behavior
 */
interface InjectOptions {
  /** Make injection optional, return null if not found */
  optional?: boolean;
  /** Only look in current injector, don't traverse hierarchy */
  self?: boolean;
  /** Skip current injector, start from parent */
  skipSelf?: boolean;
  /** Specify which injector to use as host */
  host?: boolean;
}

/**
 * Assert that code is running in an injection context
 * @param debugFn - Optional function for debug information
 */
function assertInInjectionContext(debugFn?: Function): void;

/**
 * Run function in injection context with specified injector
 * @param injector - The injector to use as context
 * @param fn - Function to run in the injection context
 * @returns The result of the function call
 */
function runInInjectionContext<T>(injector: Injector, fn: () => T): T;

Injector Classes

Core injector implementations for managing and resolving dependencies.

/**
 * Abstract base class for dependency injection containers
 */
abstract class Injector {
  /** Get dependency by token */
  abstract get<T>(token: ProviderToken<T>): T;
  
  /** Get dependency by token with default value */
  abstract get<T>(token: ProviderToken<T>, notFoundValue: T): T;
  
  /** Get dependency by token with null default */
  abstract get<T>(token: ProviderToken<T>, notFoundValue: null): T | null;

  /**
   * Create a new injector with static providers
   * @param providers - Array of provider configurations
   * @param parent - Optional parent injector
   * @returns New injector instance
   */
  static create(providers: StaticProvider[], parent?: Injector): Injector;

  /** The null injector which throws for all tokens */
  static readonly NULL: Injector;

  /** The root platform injector */
  static readonly ROOT: Injector;
}

/**
 * Environment injector for application-level services
 */
abstract class EnvironmentInjector extends Injector {
  /**
   * Destroy the injector and cleanup resources
   */
  abstract destroy(): void;

  /**
   * Callback when injector is destroyed
   */
  abstract onDestroy(callback: () => void): void;
}

/**
 * Injector that can be destroyed and cleaned up
 */
interface DestroyableInjector extends Injector {
  /** Destroy the injector and cleanup resources */
  destroy(): void;
  
  /** Register cleanup callback */
  onDestroy(callback: () => void): void;
}

Provider Types

Different types of providers for configuring dependency injection.

/**
 * Union type for all provider configurations
 */
type Provider = ClassProvider | ValueProvider | FactoryProvider | ExistingProvider | any[];

/**
 * Provider that creates instance using class constructor
 */
interface ClassProvider {
  /** Token to provide */
  provide: any;
  /** Class to instantiate */
  useClass: Type<any>;
  /** Whether to provide as multi-provider array */
  multi?: boolean;
}

/**
 * Provider that provides a static value
 */
interface ValueProvider {
  /** Token to provide */
  provide: any;
  /** Static value to provide */
  useValue: any;
  /** Whether to provide as multi-provider array */
  multi?: boolean;
}

/**
 * Provider that creates instance using factory function
 */
interface FactoryProvider {
  /** Token to provide */
  provide: any;
  /** Factory function to create instance */
  useFactory: Function;
  /** Dependencies to inject into factory function */
  deps?: any[];
  /** Whether to provide as multi-provider array */
  multi?: boolean;
}

/**
 * Provider that aliases another token
 */
interface ExistingProvider {
  /** Token to provide */
  provide: any;
  /** Existing token to alias */
  useExisting: any;
  /** Whether to provide as multi-provider array */
  multi?: boolean;
}

/**
 * Provider for platform-level static services
 */
interface StaticProvider {
  /** Token to provide */
  provide: any;
  /** Value, class, factory, or existing provider */
  useValue?: any;
  useClass?: Type<any>;
  useFactory?: Function;
  useExisting?: any;
  /** Dependencies for factory provider */
  deps?: any[];
  /** Whether to provide as multi-provider array */
  multi?: boolean;
}

/**
 * Providers for environment configuration
 */
type EnvironmentProviders = unknown;

Injection Tokens

Type-safe tokens for non-class dependencies and configuration.

/**
 * Type-safe injection token for non-class dependencies
 */
class InjectionToken<T> {
  /**
   * Create an injection token
   * @param desc - Description for debugging
   * @param options - Token configuration options
   */
  constructor(desc: string, options?: {
    /** Where to provide the token */
    providedIn?: Type<any> | 'root' | 'platform' | 'any';
    /** Factory function for creating the value */
    factory?: () => T;
  });

  /** String representation of the token */
  toString(): string;
}

/**
 * Provider token type union
 */
type ProviderToken<T> = Type<T> | InjectionToken<T> | string;

Forward References

Utilities for resolving circular dependencies and forward references.

/**
 * Create forward reference to resolve circular dependencies
 * @param forwardRefFn - Function returning the referenced type
 * @returns Forward reference wrapper
 */
function forwardRef(forwardRefFn: ForwardRefFn): Type<any>;

/**
 * Resolve forward reference to actual value
 * @param type - Type or forward reference to resolve
 * @returns Resolved type
 */
function resolveForwardRef<T>(type: T): T;

/**
 * Function type for forward references
 */
interface ForwardRefFn {
  (): any;
}

Provider Helper Functions

Utility functions for creating and configuring providers.

/**
 * Import providers from NgModule for standalone components
 * @param ngModule - Module to import providers from
 * @returns Environment providers
 */
function importProvidersFrom(...ngModule: Type<any>[]): EnvironmentProviders;

/**
 * Create environment-level provider configuration
 * @param providers - Array of providers
 * @returns Environment providers
 */
function makeEnvironmentProviders(providers: Provider[]): EnvironmentProviders;

/**
 * Provide environment initialization functions
 * @param initializerFn - Initialization function
 * @returns Environment providers
 */
function provideEnvironmentInitializer(initializerFn: () => void): EnvironmentProviders;

Built-in Injection Tokens

Standard injection tokens provided by Angular.

/** Token for the current injector instance */
const INJECTOR: InjectionToken<Injector>;

/** Token for environment initialization callbacks */
const ENVIRONMENT_INITIALIZER: InjectionToken<(() => void)[]>;

/** Token for application initialization functions */
const APP_INITIALIZER: InjectionToken<(() => Observable<unknown> | Promise<unknown> | void)[]>;

/** Token for application bootstrap listeners */  
const APP_BOOTSTRAP_LISTENER: InjectionToken<((compRef: ComponentRef<any>) => void)[]>;

/** Token for unique application identifier */
const APP_ID: InjectionToken<string>;

/** Token for platform identifier */
const PLATFORM_ID: InjectionToken<Object>;

/** Token for platform initialization functions */
const PLATFORM_INITIALIZER: InjectionToken<(() => void)[]>;

/** Token for the Document object */
const DOCUMENT: InjectionToken<Document>;

/** Token for locale identifier */
const LOCALE_ID: InjectionToken<string>;

/** Token for default currency code */
const DEFAULT_CURRENCY_CODE: InjectionToken<string>;

Usage Examples

Basic Service with Injection

import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  private http = inject(HttpClient);

  getUsers() {
    return this.http.get<User[]>('/api/users');
  }

  getUser(id: string) {
    return this.http.get<User>(`/api/users/${id}`);
  }
}

Custom Injection Token

import { InjectionToken, inject, Injectable } from '@angular/core';

// Define configuration interface
interface AppConfig {
  apiUrl: string;
  timeout: number;
  retries: number;
}

// Create injection token
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config', {
  providedIn: 'root',
  factory: () => ({
    apiUrl: 'http://localhost:3000/api',
    timeout: 5000,
    retries: 3
  })
});

// Use in service
@Injectable({
  providedIn: 'root'
})
export class ApiService {
  private config = inject(APP_CONFIG);

  makeRequest(endpoint: string) {
    console.log(`Making request to: ${this.config.apiUrl}${endpoint}`);
    // Implementation...
  }
}

Provider Configuration

import { NgModule, InjectionToken } from '@angular/core';

// Factory provider
const RANDOM_GENERATOR = new InjectionToken<() => number>('random.generator');

function randomGeneratorFactory(): () => number {
  return () => Math.random();
}

// Class provider
class LoggerService {
  log(message: string) {
    console.log(message);
  }
}

class FileLoggerService extends LoggerService {
  log(message: string) {
    // Save to file instead of console
    this.saveToFile(message);
  }

  private saveToFile(message: string) {
    // File logging implementation
  }
}

@NgModule({
  providers: [
    // Value provider
    { provide: 'API_URL', useValue: 'https://api.example.com' },
    
    // Class provider
    { provide: LoggerService, useClass: FileLoggerService },
    
    // Factory provider
    { 
      provide: RANDOM_GENERATOR, 
      useFactory: randomGeneratorFactory 
    },
    
    // Existing provider (alias)
    { provide: 'LOGGER', useExisting: LoggerService },
    
    // Multi provider
    { 
      provide: 'FEATURE_FLAGS', 
      useValue: 'feature-a', 
      multi: true 
    },
    { 
      provide: 'FEATURE_FLAGS', 
      useValue: 'feature-b', 
      multi: true 
    }
  ]
})
export class AppModule { }

Optional and Hierarchical Injection

import { Component, inject, Optional, Self, SkipSelf } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `<div>Child Component</div>`,
  providers: [
    { provide: 'LOCAL_SERVICE', useValue: 'child-local' }
  ]
})
export class ChildComponent {
  // Required injection - will throw if not found
  required = inject(UserService);

  // Optional injection - returns null if not found
  optional = inject(CacheService, { optional: true });

  // Self injection - only look in current injector
  local = inject('LOCAL_SERVICE', { self: true });

  // Skip self - start from parent injector
  parentService = inject(ParentService, { skipSelf: true });

  // Host injection - look in host element's injector
  hostService = inject(HostService, { host: true });

  constructor() {
    console.log('Optional service:', this.optional); // May be null
    console.log('Local service:', this.local);       // 'child-local'
  }
}

Environment Providers

import { 
  bootstrapApplication, 
  importProvidersFrom, 
  makeEnvironmentProviders,
  provideEnvironmentInitializer 
} from '@angular/core';
import { RouterModule } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';

// Custom environment providers
const customProviders = makeEnvironmentProviders([
  { provide: 'API_URL', useValue: 'https://api.example.com' },
  { provide: UserService, useClass: UserService }
]);

// Environment initializer
const initializeApp = provideEnvironmentInitializer(() => {
  console.log('Application environment initialized');
});

// Bootstrap with providers
bootstrapApplication(AppComponent, {
  providers: [
    // Import from modules
    importProvidersFrom(
      RouterModule.forRoot(routes),
      HttpClientModule
    ),
    
    // Custom providers
    customProviders,
    
    // Environment initializer
    initializeApp
  ]
});

Injection in Functions

import { inject, runInInjectionContext, Injector } from '@angular/core';

// Standalone function that uses injection
function createUserManager() {
  const userService = inject(UserService);
  const logger = inject(LoggerService);
  
  return {
    getUser: (id: string) => {
      logger.log(`Fetching user ${id}`);
      return userService.getUser(id);
    }
  };
}

// Using function with injection context
@Component({...})
export class MyComponent {
  private injector = inject(Injector);
  
  createManager() {
    return runInInjectionContext(this.injector, () => {
      return createUserManager();
    });
  }
}