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

utilities-helpers.mddocs/

Utilities & Helpers

Angular Core provides various utility functions, classes, and helpers for common development tasks including debugging, error handling, version information, and state management.

Capabilities

Version Information

Access to Angular version details for debugging and compatibility checks.

/**
 * Angular version information
 */
class Version {
  constructor(
    public readonly full: string,
    public readonly major: string,
    public readonly minor: string,
    public readonly patch: string
  );
}

/**
 * Current Angular version instance
 */
const VERSION: Version;

Error Handling

Global error handling interfaces and utilities for managing application errors.

/**
 * Interface for handling uncaught errors in Angular applications
 */
abstract class ErrorHandler {
  /**
   * Handle an error
   * @param error - The error to handle
   */
  abstract handleError(error: any): void;
}

/**
 * Provides global error listeners for browser environments
 * @returns Environment providers for global error handling
 */
function provideBrowserGlobalErrorListeners(): EnvironmentProviders;

Debug Utilities

Debugging utilities for inspecting component and element state during development.

/**
 * Debug wrapper for DOM nodes
 */
class DebugNode {
  /** Native DOM node */
  readonly nativeNode: any;
  /** Parent debug node */
  readonly parent: DebugElement | null;
  /** Injector for this node */
  readonly injector: Injector;
  /** Component instance (if any) */
  readonly componentInstance: any;
  /** Node context */
  readonly context: any;
  /** Child debug nodes */
  readonly childNodes: DebugNode[];
  /** Listeners attached to this node */
  readonly listeners: EventListener[];
}

/**
 * Debug wrapper for DOM elements (extends DebugNode)
 */
class DebugElement extends DebugNode {
  /** Native DOM element */
  readonly nativeElement: any;
  /** Element name/tag */
  readonly name: string;
  /** Element attributes */
  readonly attributes: {[key: string]: string | null};
  /** Element classes */
  readonly classes: {[key: string]: boolean};
  /** Element styles */
  readonly styles: {[key: string]: string | null};
  /** Child elements */
  readonly children: DebugElement[];
  /** Element properties */
  readonly properties: {[key: string]: any};

  /**
   * Query for child element by selector
   * @param predicate - CSS selector or predicate function
   * @returns First matching child element
   */
  query(predicate: string | Predicate<DebugElement>): DebugElement | null;

  /**
   * Query for all matching child elements
   * @param predicate - CSS selector or predicate function
   * @returns Array of matching child elements
   */
  queryAll(predicate: string | Predicate<DebugElement>): DebugElement[];

  /**
   * Query for all child elements
   * @returns Array of all child elements
   */
  queryAllNodes(predicate: Predicate<DebugNode>): DebugNode[];

  /**
   * Trigger event on element
   * @param eventName - Name of event to trigger
   * @param eventObj - Event object
   */
  triggerEventHandler(eventName: string, eventObj?: any): void;
}

/**
 * Get debug node for a DOM node
 * @param element - DOM node to get debug info for
 * @returns Debug node or null if not found
 */
function getDebugNode(element: any): DebugNode | null;

/**
 * Extract native elements from debug elements
 * @param debugEls - Array of debug elements
 * @returns Array of native DOM elements
 */
function asNativeElements(debugEls: DebugElement[]): any[];

/**
 * Predicate function type for debug queries
 */
type Predicate<T> = (value: T) => boolean;

Transfer State

State transfer utilities for sharing data between server and client during SSR.

/**
 * Service for transferring state from server to client
 */
class TransferState {
  /**
   * Get value from transfer state
   * @param key - State key
   * @param defaultValue - Default value if key not found
   * @returns Stored value or default
   */
  get<T>(key: StateKey<T>, defaultValue: T): T;

  /**
   * Set value in transfer state
   * @param key - State key
   * @param value - Value to store
   */
  set<T>(key: StateKey<T>, value: T): void;

  /**
   * Remove value from transfer state
   * @param key - State key to remove
   */
  remove<T>(key: StateKey<T>): void;

  /**
   * Check if key exists in transfer state
   * @param key - State key to check
   * @returns True if key exists
   */
  hasKey<T>(key: StateKey<T>): boolean;

  /**
   * Called when transfer state should be serialized
   */
  onSerialize<T>(key: StateKey<T>, callback: () => T): void;
}

/**
 * Key for transfer state values
 */
class StateKey<T> {
  constructor(public readonly id: string) {}
}

/**
 * Create a state key for transfer state
 * @param stateId - Unique identifier for the state
 * @returns State key instance
 */
function makeStateKey<T = void>(stateId: string): StateKey<T>;

Testability

Testability utilities for supporting end-to-end testing frameworks.

/**
 * Service that tracks pending asynchronous operations
 */
class Testability {
  /**
   * Check if application is stable (no pending async operations)
   * @returns True if application is stable
   */
  isStable(): boolean;

  /**
   * Wait for application to become stable
   * @param doneCb - Callback when application becomes stable
   * @param timeout - Timeout in milliseconds
   * @param updateCb - Optional progress callback
   */
  whenStable(doneCb: Function, timeout?: number, updateCb?: Function): void;

  /**
   * Get pending async operations count
   * @returns Number of pending operations
   */
  getPendingRequestCount(): number;

  /**
   * Find providers in the application
   * @param using - Query selector or provider token
   * @param provider - Provider to find
   * @returns Array of provider instances
   */
  findProviders(using: any, provider: string, exactMatch: boolean): any[];
}

/**
 * Registry for testability services
 */
class TestabilityRegistry {
  /**
   * Register testability service for a root element
   * @param token - Root element or token
   * @param testability - Testability service
   */
  registerApplication(token: any, testability: Testability): void;

  /**
   * Unregister testability service
   * @param token - Root element or token
   */
  unregisterApplication(token: any): void;

  /**
   * Get testability service for element
   * @param elem - DOM element
   * @returns Testability service or null
   */
  getTestability(elem: any): Testability | null;

  /**
   * Get all registered testability services
   * @returns Array of testability services
   */
  getAllTestabilities(): Testability[];

  /**
   * Get all root elements with testability
   * @returns Array of root elements
   */
  getAllRootElements(): any[];

  /**
   * Find testability service in tree
   * @param elem - Starting DOM element
   * @param findInAncestors - Whether to search ancestors
   * @returns Testability service or null
   */
  findTestabilityInTree(elem: Node, findInAncestors?: boolean): Testability | null;
}

/**
 * Set global testability getter function
 * @param getter - Function to get testability registry
 */
function setTestabilityGetter(getter: GetTestabilityFunction): void;

/**
 * Function type for getting testability registry
 */
type GetTestabilityFunction = () => TestabilityRegistry;

Security Context

Security-related utilities and enums for sanitization and XSS prevention.

/**
 * Security contexts for value sanitization
 */
enum SecurityContext {
  /** No sanitization needed */
  NONE = 0,
  /** HTML content sanitization */
  HTML = 1,
  /** CSS style sanitization */
  STYLE = 2,
  /** JavaScript/Script sanitization */
  SCRIPT = 3,
  /** URL sanitization */
  URL = 4,
  /** Resource URL sanitization */
  RESOURCE_URL = 5
}

/**
 * Interface for value sanitization
 */
abstract class Sanitizer {
  /**
   * Sanitize a value for a given security context
   * @param context - Security context
   * @param value - Value to sanitize
   * @returns Sanitized value
   */
  abstract sanitize(context: SecurityContext, value: string | SafeValue): string | null;
}

/**
 * Marker interface for safe values that don't need sanitization
 */
interface SafeValue {}

Internationalization Support

Core i18n tokens and configuration for internationalization.

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

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

/**
 * Token for translation data
 */
const TRANSLATIONS: InjectionToken<string>;

/**
 * Token for translation format
 */
const TRANSLATIONS_FORMAT: InjectionToken<string>;

/**
 * Strategy for handling missing translations
 */
enum MissingTranslationStrategy {
  /** Throw error on missing translation */
  Error = 0,
  /** Show warning for missing translation */
  Warning = 1,
  /** Ignore missing translations */
  Ignore = 2
}

Hydration Support

Client-side hydration utilities for server-side rendered applications.

/**
 * Provides client-side hydration support
 * @param features - Optional hydration features
 * @returns Environment providers for hydration
 */
function provideClientHydration(...features: HydrationFeature[]): EnvironmentProviders;

/**
 * Feature for event replay during hydration
 * @returns Hydration feature for event replay
 */
function withEventReplay(): HydrationFeature;

/**
 * Feature to disable HTTP transfer cache
 * @returns Hydration feature to disable transfer cache
 */
function withNoHttpTransferCache(): HydrationFeature;

/**
 * Base interface for hydration features
 */
interface HydrationFeature {
  kind: string;
  providers?: Provider[];
}

Type Utilities

Core type utilities and interfaces used throughout Angular.

/**
 * Interface representing a class constructor
 */
interface Type<T> extends Function {
  new (...args: any[]): T;
}

/**
 * Interface representing an abstract class
 */
interface AbstractType<T> extends Function {
  prototype: T;
}

/**
 * Union type for provider tokens
 */
type ProviderToken<T> = Type<T> | InjectionToken<T> | string;

/**
 * Interface for type decorators
 */
interface TypeDecorator {
  <T extends Type<any>>(type: T): T;
  (target: Object, propertyKey?: string | symbol, parameterIndex?: number): void;
}

/**
 * Forward reference function for circular dependencies
 * @param forwardRefFn - Function that returns the reference
 * @returns Forward reference object
 */
function forwardRef(forwardRefFn: ForwardRefFn): any;

/**
 * Function type for forward references
 */
type ForwardRefFn = () => any;

Usage Examples

Error Handling

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

@Injectable()
export class CustomErrorHandler extends ErrorHandler {
  handleError(error: any): void {
    // Log to external service
    console.error('Global error:', error);
    
    // Report to error tracking service
    this.reportError(error);
    
    // Show user-friendly message
    this.showUserNotification('An unexpected error occurred');
  }

  private reportError(error: any): void {
    // Send to error tracking service like Sentry, Rollbar, etc.
    fetch('/api/errors', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        message: error.message,
        stack: error.stack,
        timestamp: new Date().toISOString(),
        userAgent: navigator.userAgent
      })
    });
  }

  private showUserNotification(message: string): void {
    // Show toast or notification to user
    const notification = document.createElement('div');
    notification.textContent = message;
    notification.className = 'error-notification';
    document.body.appendChild(notification);
    
    setTimeout(() => notification.remove(), 5000);
  }
}

// Register custom error handler
@NgModule({
  providers: [
    { provide: ErrorHandler, useClass: CustomErrorHandler }
  ]
})
export class AppModule {}

Debug Utilities

import { Component, ElementRef, viewChild, AfterViewInit } from '@angular/core';
import { getDebugNode, DebugElement } from '@angular/core';

@Component({
  selector: 'app-debug-example',
  template: `
    <div #container class="container">
      <button #btn (click)="handleClick()" [disabled]="isDisabled">
        Click me
      </button>
      <p #message>{{messageText}}</p>
    </div>
  `
})
export class DebugExampleComponent implements AfterViewInit {
  containerRef = viewChild.required<ElementRef>('container');
  buttonRef = viewChild.required<ElementRef>('btn');
  
  isDisabled = false;
  messageText = 'Hello World';

  ngAfterViewInit(): void {
    if (isDevMode()) {
      this.inspectElements();
    }
  }

  private inspectElements(): void {
    // Get debug nodes for inspection
    const containerEl = this.containerRef().nativeElement;
    const buttonEl = this.buttonRef().nativeElement;
    
    const containerDebug = getDebugNode(containerEl) as DebugElement;
    const buttonDebug = getDebugNode(buttonEl) as DebugElement;
    
    console.log('Container debug info:', {
      name: containerDebug.name,
      classes: containerDebug.classes,
      children: containerDebug.children.map(child => child.name)
    });
    
    console.log('Button debug info:', {
      name: buttonDebug.name,
      properties: buttonDebug.properties,
      attributes: buttonDebug.attributes,
      listeners: buttonDebug.listeners.map(l => l.name)
    });
    
    // Query for elements
    const allButtons = containerDebug.queryAll('button');
    console.log('Found buttons:', allButtons.length);
    
    // Programmatically trigger events (useful for testing)
    if (buttonDebug) {
      setTimeout(() => {
        buttonDebug.triggerEventHandler('click', null);
      }, 2000);
    }
  }

  handleClick(): void {
    this.messageText = 'Button was clicked!';
    console.log('Button clicked at:', new Date());
  }
}

Transfer State for SSR

import { Component, Inject, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
import { TransferState, makeStateKey } from '@angular/core';
import { HttpClient } from '@angular/common/http';

interface UserData {
  id: number;
  name: string;
  email: string;
}

const USER_DATA_KEY = makeStateKey<UserData>('userData');

@Component({
  selector: 'app-ssr-example',
  template: `
    <div>
      <h3>Server-Side Rendered Data</h3>
      <div *ngIf="userData">
        <p>Name: {{userData.name}}</p>
        <p>Email: {{userData.email}}</p>
        <p>Loaded from: {{dataSource}}</p>
      </div>
    </div>
  `
})
export class SsrExampleComponent {
  userData: UserData | null = null;
  dataSource = '';

  constructor(
    private transferState: TransferState,
    private http: HttpClient,
    @Inject(PLATFORM_ID) private platformId: Object
  ) {}

  ngOnInit(): void {
    if (isPlatformBrowser(this.platformId)) {
      // Try to get data from transfer state first
      this.userData = this.transferState.get(USER_DATA_KEY, null);
      
      if (this.userData) {
        this.dataSource = 'Transfer State (SSR)';
        // Clean up transfer state
        this.transferState.remove(USER_DATA_KEY);
      } else {
        // Fallback to client-side fetch
        this.loadUserData();
        this.dataSource = 'Client-side API';
      }
    } else if (isPlatformServer(this.platformId)) {
      // Server-side: load data and store in transfer state
      this.loadUserDataForSSR();
    }
  }

  private loadUserData(): void {
    this.http.get<UserData>('/api/user').subscribe(
      data => this.userData = data
    );
  }

  private loadUserDataForSSR(): void {
    this.http.get<UserData>('/api/user').subscribe(
      data => {
        this.userData = data;
        this.dataSource = 'Server-side';
        // Store in transfer state for client hydration
        this.transferState.set(USER_DATA_KEY, data);
      }
    );
  }
}

Version Information

import { Component } from '@angular/core';
import { VERSION } from '@angular/core';

@Component({
  selector: 'app-version-info',
  template: `
    <div class="version-info">
      <h3>Application Information</h3>
      <table>
        <tr>
          <td>Angular Version:</td>
          <td>{{angularVersion.full}}</td>
        </tr>
        <tr>
          <td>Major Version:</td>
          <td>{{angularVersion.major}}</td>
        </tr>
        <tr>
          <td>Minor Version:</td>
          <td>{{angularVersion.minor}}</td>
        </tr>
        <tr>
          <td>Patch Version:</td>
          <td>{{angularVersion.patch}}</td>
        </tr>
        <tr>
          <td>Compatibility:</td>
          <td [class.compatible]="isCompatible" [class.incompatible]="!isCompatible">
            {{compatibilityStatus}}
          </td>
        </tr>
      </table>
    </div>
  `,
  styles: [`
    .version-info {
      border: 1px solid #ccc;
      padding: 16px;
      border-radius: 4px;
      max-width: 400px;
    }
    table {
      width: 100%;
      border-collapse: collapse;
    }
    td {
      padding: 4px 8px;
      border-bottom: 1px solid #eee;
    }
    .compatible {
      color: green;
    }
    .incompatible {
      color: red;
    }
  `]
})
export class VersionInfoComponent {
  angularVersion = VERSION;
  
  get isCompatible(): boolean {
    const major = parseInt(this.angularVersion.major);
    return major >= 17; // Example: require Angular 17+
  }
  
  get compatibilityStatus(): string {
    return this.isCompatible ? 'Compatible' : 'Requires Angular 17+';
  }
}

Custom Testability

import { Injectable, NgZone } from '@angular/core';
import { Testability, TestabilityRegistry } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class CustomTestability extends Testability {
  private pendingOperations = new Set<string>();

  constructor(private ngZone: NgZone) {
    super();
  }

  isStable(): boolean {
    return this.pendingOperations.size === 0 && this.ngZone.isStable;
  }

  whenStable(callback: Function, timeout?: number, updateCallback?: Function): void {
    const startTime = Date.now();
    const timeoutMs = timeout || 10000;
    
    const checkStability = () => {
      if (this.isStable()) {
        callback();
        return;
      }
      
      if (Date.now() - startTime > timeoutMs) {
        callback('Timeout waiting for stability');
        return;
      }
      
      if (updateCallback) {
        updateCallback(this.getPendingRequestCount());
      }
      
      setTimeout(checkStability, 100);
    };
    
    checkStability();
  }

  getPendingRequestCount(): number {
    return this.pendingOperations.size;
  }

  // Custom methods for tracking operations
  trackOperation(operationId: string): void {
    this.pendingOperations.add(operationId);
  }

  completeOperation(operationId: string): void {
    this.pendingOperations.delete(operationId);
  }
}

// Service that uses custom testability
@Injectable({
  providedIn: 'root'
})
export class DataService {
  constructor(
    private http: HttpClient,
    private testability: CustomTestability
  ) {}

  async loadData(): Promise<any> {
    const operationId = `load-data-${Date.now()}`;
    this.testability.trackOperation(operationId);
    
    try {
      const data = await this.http.get('/api/data').toPromise();
      return data;
    } finally {
      this.testability.completeOperation(operationId);
    }
  }
}