Skip to main content

NcachedService

The single injectable that powers ng-ncached. Provided in 'root', so it's a singleton across the entire application.

import { NcachedService } from 'ng-ncached';

Public methods

MethodPurpose
setStore a value under a key path, optionally with TTL.
getRead a value back. Throws on miss / expired.
getOrDefaultRead a value back, returning a default on miss / expired. Never throws for misses.
hasCheck if a non-expired entry exists at a path. Boolean. Never throws.
cacheObservableCache the result of an Observable, with optional TTL, fallback, and request dedup.
keysList every complete key path under an optional prefix.
sizeCount non-expired entries across the cache.
removeDelete a single cache entry. No-op on missing path.
clearDelete an entire subtree / namespace. No-op on missing path.
clearAllWipe the in-memory cache (and localStorage entry if persistence is on).

set

set<T = any>(value: T, ...args: Array<string | ISetOptions>): void

Stores value in the cache under the given key path.

  • value — the value to store. No constraints.
  • args — at least two strings. The last string is the Map key; everything before it is the namespace path. An optional ISetOptions object may be passed as the last argument.
  • Returnsvoid.

Throws

ErrorWhen
NcachedServiceErrors.InsufficientsKeysProvidedErrorFewer than two string keys were passed
NcachedServiceErrors.UncloneableValueErrorThe value cannot be deep-cloned by structuredClone (functions, DOM nodes, etc.)

Cloning — since v1.1.0, set() deep-clones the value before storing it via structuredClone. Mutating your source object after the call does not affect the cached value.

Example

this._cache.set<string>('Hello', 'app', 'greeting');
this._cache.set<IUser>(user, 'users', 'byId', user.id);
this._cache.set<string>(token, 'auth', 'token', { ttl: 60_000 });

See Setting values and TTL & expiration.


get

get<T = any>(...keys: string[]): T

Reads a value out of the cache using the same key path it was stored under.

  • keys — at least two strings. Must match a path used in a previous set().
  • T — the expected type of the returned value. Strongly recommended.
  • Returns — the cached value, typed as T.

Throws

ErrorWhen
NcachedServiceErrors.InsufficientsKeysProvidedErrorFewer than two keys were passed
NcachedServiceErrors.KeyNotFoundA namespace key in the path doesn't exist
NcachedServiceErrors.MapNotFoundA key in the path exists but doesn't point to a Map
NcachedServiceErrors.ValueNotFoundThe map entry is missing or the entry has expired (TTL)
NcachedServiceErrors.UncloneableValueErrorThe cached value cannot be deep-cloned by structuredClone

When an entry is expired, it is removed from the underlying Map before throwing.

Cloning — since v1.1.0, get() returns a deep clone of the cached value via structuredClone. Mutating the returned object does not affect the cache, and two consecutive get() calls produce two independent copies.

Example

const greeting = this._cache.get<string>('app', 'greeting');
const user = this._cache.get<IUser>('users', 'byId', 'usr_42');

See Getting values.


getOrDefault

getOrDefault<T = any>(defaultValue: T, ...keys: string[]): T

Reads a value, returning defaultValue if the entry is missing or expired. Never throws for cache misses.

  • defaultValue — fallback returned on any cache miss.
  • keys — same rules as get().
  • Returns — the cached value or defaultValue.

Example

const theme = this._cache.getOrDefault<string>('light', 'ui', 'theme');

This is the safe, ergonomic accessor — prefer it over wrapping get() in a try/catch.


has

has(...keys: string[]): boolean

Returns true if a non-expired entry exists at the given path, false otherwise. Never throws — invalid call shapes (fewer than 2 keys), missing paths, and expired entries all return false.

  • keys — same rules as get(). Min 2.

Pure read — has() does not delete expired entries it encounters. If you want lazy cleanup of expired entries as a side effect, use get() (which throws and deletes) or getOrDefault() (which deletes silently).

Example

this._cache.set('Ada', 'users', 'currentName');
this._cache.has('users', 'currentName'); // true
this._cache.has('users', 'missing'); // false

cacheObservable

cacheObservable<T = any>(
source: Observable<T>,
options: ICacheObservableOptions<T>,
...keys: string[]
): Observable<T>

Caches the result of an Observable source. On cache hit, emits the cached value via of() without subscribing to the source. On cache miss, subscribes to source, stores the emitted value (with optional TTL), and emits it.

  • source — the upstream observable, typically an HttpClient call.
  • options{ ttl?: number; defaultValue?: T }. See ICacheObservableOptions.
  • keys — same key path rules as get/set. Min 2.
  • Returns — an Observable<T> that emits exactly once.

Behaviour

  • Concurrent calls with the same keys share one subscription via shareReplay({ bufferSize: 1, refCount: true }). The in-flight entry is keyed by keys.join('::') and cleaned up on completion or error.
  • Source error + defaultValue provided → emits defaultValue.
  • Source error, no defaultValue → re-throws.

Example

this._cache.cacheObservable<IUser[]>(
this._http.get<IUser[]>('/api/users'),
{ ttl: 30_000 },
'api', 'users',
).subscribe(users => console.log(users));

See Caching observables.


remove

remove(...keys: string[]): void

Removes a single cache entry. The last key is the Map key; preceding keys navigate the hierarchy. No-op if the path or key does not exist. Does not throw.

Example

this._cache.remove('users', 'currentName');
this._cache.remove('nonexistent', 'key'); // no-op

If fewer than two keys are passed, the call is a no-op (no exception).


clear

clear(...keys: string[]): void

Removes an entire subtree from the cache. Calling with one key drops a top-level namespace; calling with N keys drops the deepest node at that path. No-op on missing paths.

Example

this._cache.clear('users'); // drops all 'users'
this._cache.clear('users', 'byOrg', 'org-1'); // drops org-1 only
this._cache.clear(); // no-op (use clearAll() to wipe)

clearAll

clearAll(): void

Wipes the entire in-memory cache. If persistence is enabled, also removes the configured localStorage entry. The localStorage removal is best-effort — if it fails, the in-memory cache is still cleared.

Example

this._cache.clearAll();

keys

keys(...prefix: string[]): string[][]

Lists every complete key path under the given prefix. Each returned path is a full key chain (prefix + leaf), suitable for direct use with get/set/remove. Expired entries are skipped (without being deleted). Returns an empty array when the prefix doesn't exist.

  • prefix — optional namespace prefix to scope the listing. Pass nothing to list every path.

Example

this._cache.set('Ada', 'users', 'byOrg', 'org-1', 'u1');
this._cache.set('Alan', 'users', 'byOrg', 'org-1', 'u2');
this._cache.set('Bob', 'users', 'byOrg', 'org-2', 'u1');

this._cache.keys('users', 'byOrg', 'org-1');
// [['users', 'byOrg', 'org-1', 'u1'], ['users', 'byOrg', 'org-1', 'u2']]

this._cache.keys(); // every path in the cache

size

size(): number

Returns the total count of non-expired entries across the entire cache. Pure read — does not delete the expired entries it skips during traversal.

Example

this._cache.set('a', 'mod', 'k1');
this._cache.set('b', 'mod', 'k2');
this._cache.set('c', 'other', 'k1', 'k2');
this._cache.size(); // 3

Constructor

constructor(@Optional() @Inject(NCACHED_CONFIG) config: INcachedConfig | null)

You don't call this directly — Angular's DI does. If provideNcachedConfig() is in the providers, the resolved config is injected; otherwise null is used and the service runs in pure in-memory mode.

When config.persistence.enabled is true, the constructor:

  1. Calls _hydrate() — reads localStorage, decompresses, deserialises, drops expired entries.
  2. Registers a beforeunload listener that calls _persist().

Lifecycle and scope

NcachedService is providedIn: 'root', so:

  • It's a singleton across the whole app.
  • The internal cache lives in memory for the duration of the page session — and across reloads if persistence is enabled.
  • There's no built-in cross-tab synchronisation.

For multiple isolated cache instances (e.g. per feature), provide NcachedService at a lower injector level.