Core operators and utilities for the ngrx platform
npx @tessl/cli install tessl/npm-ngrx--core@1.2.0@ngrx/core provides essential RxJS operators and utilities for the NgRx platform, a reactive state management library for Angular applications. It includes state selection operators with automatic distinctness checking, Angular zone management operators, and functional composition utilities that integrate seamlessly with RxJS streams.
npm install @ngrx/coreimport { select, enterZone, leaveZone, compose } from "@ngrx/core";For CommonJS:
const { select, enterZone, leaveZone, compose } = require("@ngrx/core");import { Observable } from "rxjs";
import { select, enterZone, leaveZone, compose } from "@ngrx/core";
// State selection with automatic distinctness
const state$ = new Observable(/* state stream */);
const todoFilter$ = state$.let(select('filter'));
const todoTitle$ = state$.let(select('todos', 'a', 'title'));
const mappedState$ = state$.let(select(state => state.user.name));
// Zone management
const zone = {
run: (fn) => fn(),
runOutsideAngular: (fn) => fn()
};
const enterZoned$ = stream$.let(enterZone(zone));
const leaveZoned$ = stream$.let(leaveZone(zone));
// Function composition
const processData = compose(
(data) => data.toUpperCase(),
(data) => data.trim(),
(data) => data.replace(/\\s+/g, ' ')
);
const result = processData(" hello world ");The select operator extracts specific slices of state with automatic distinctness checking to prevent unnecessary re-renders.
/**
* Select operator for extracting state slices with automatic distinctness
* Used with Observable.prototype.let() method
* @param pathOrMapFn - String path or mapping function
* @param paths - Additional path segments for nested property access
* @returns Operator function for use with .let()
*/
function select<T, R>(pathOrMapFn: string | ((state: T) => R), ...paths: string[]): Observable<R>;
interface SelectSignature<T> {
<R>(...paths: string[]): Observable<R>;
<R>(mapFn: (state: T) => R): Observable<R>;
}Usage Examples:
import { Observable } from "rxjs";
import { select } from "@ngrx/core";
const state = {
todos: { a: { title: 'First Todo' }, b: { title: 'Second Todo' } },
filter: 'all'
};
// String path selection
const filter$ = Observable.of(state).let(select('filter'));
// Nested path selection
const todoTitle$ = Observable.of(state).let(select('todos', 'a', 'title'));
// Function-based selection
const todoB$ = Observable.of(state).let(select(s => s.todos.b.title));The enterZone operator ensures emissions are executed within Angular's zone context for proper change detection.
/**
* Enter Angular zone for emissions to trigger change detection
* Used with Observable.prototype.let() method
* @param zone - Zone-like object with run method
* @returns Operator function for use with .let()
*/
function enterZone<T>(zone: ZoneInterface): Observable<T>;
interface EnterZoneSignature<T> {
(zone: ZoneInterface): Observable<T>;
}
interface ZoneInterface {
run: (fn: any) => any;
}The leaveZone operator ensures emissions are executed outside Angular's zone context to avoid triggering change detection.
/**
* Leave Angular zone for emissions to avoid change detection
* Used with Observable.prototype.let() method
* @param zone - Zone-like object with runOutsideAngular method
* @returns Operator function for use with .let()
*/
function leaveZone<T>(zone: NgZoneInterface): Observable<T>;
interface LeaveZoneSignature<T> {
(zone: NgZoneInterface): Observable<T>;
}
interface NgZoneInterface {
runOutsideAngular: (fn: any) => any;
}The compose utility provides type-safe functional composition for chaining transformation functions.
/**
* Compose functions right-to-left with full type safety
* @param functions - Functions to compose, applied right-to-left
* @returns Composed function that applies all transformations
*/
const compose: ComposeSignature;
interface ComposeSignature {
<A>(): (i: A) => A;
<A, B>(b: (i: A) => B): (i: A) => B;
<A, B, C>(c: (i: B) => C, b: (i: A) => B): (i: A) => C;
<A, B, C, D>(d: (i: C) => D, c: (i: B) => C, b: (i: A) => B): (i: A) => D;
<A, B, C, D, E>(e: (i: D) => E, d: (i: C) => D, c: (i: B) => C, b: (i: A) => B): (i: A) => E;
<A, B, C, D, E, F>(f: (i: E) => F, e: (i: D) => E, d: (i: C) => D, c: (i: B) => C, b: (i: A) => B): (i: A) => F;
(...fns: any[]): (input: any) => any;
}Usage Example:
import { compose } from "@ngrx/core";
const double = (i: number) => 2 * i;
const add = (amount: number) => (i: number) => i + amount;
const toString = (i: number) => `${i}`;
// Compose functions right-to-left
const processNumber = compose(toString, add(3), double);
const result = processNumber(3); // "9" (3 * 2 + 3 = "9")
// Identity function with no arguments
const identity = compose();
console.log(identity(42)); // 42For users who prefer prototype-style operators, @ngrx/core provides optional prototype extensions:
// Import to add methods to Observable.prototype
import "@ngrx/core/src/add/operator/select";
import "@ngrx/core/src/add/operator/enterZone";
import "@ngrx/core/src/add/operator/leaveZone";
// Now available as methods
state$.select('todos');
stream$.enterZone(zone);
stream$.leaveZone(zone);// Internal operator implementation classes (not directly exposed)
class EnterZoneOperator<T> implements Operator<T, T> {
constructor(private _zone: ZoneInterface);
call(subscriber: Subscriber<T>, source: any): any;
}
class LeaveZoneOperator<T> implements Operator<T, T> {
constructor(private _zone: NgZoneInterface);
call(subscriber: Subscriber<T>, source: any): any;
}
// Utility subject for immediate value emission
class SyncSubject<T> extends ReplaySubject<T> {
constructor(value: T);
}The select operator includes built-in error handling:
pathOrMapFn is neither a string nor a functionpluck, map, distinctUntilChangedObservable, Operator, Subscriber, ReplaySubject