Setting values
NcachedService.set() writes a value into the cache under one or more keys. The last string key is always the key inside a Map; every key before it acts as a namespace.
Signature
set<T = any>(value: T, ...args: Array<string | ISetOptions>): void
value— the value you want to store. Anything goes: primitives, objects, observables, class instances.args— at least two string keys, optionally followed by anISetOptionsobject as the last argument.
ISetOptions currently has one field: { ttl?: number } (milliseconds). See TTL & expiration for full details. The rest of this page focuses on the basics — no TTL.
Calling set() with fewer than two string keys throws NcachedServiceErrors.InsufficientsKeysProvidedError. See Error handling.
Basic example: one namespace
This stores 'Ada Lovelace' under the key 'currentName' inside the 'users' namespace:
this._cache.set('Ada Lovelace', 'users', 'currentName');
Internally, the cache now looks like:
{
users: Map { 'currentName' => { value: 'Ada Lovelace', expiresAt: null } }
}
Each value is wrapped in an ICacheEntry with an expiresAt field — get() unwraps this for you, so you never see the wrapper. null means "never expires".
Storing complex objects
Values are stored by reference — there's no serialization at this layer, so use whatever shape works for your app:
interface IUser {
email: string;
id: string;
name: string;
}
const user: IUser = {
email: 'ada@example.com',
id: 'usr_42',
name: 'Ada Lovelace',
};
this._cache.set<IUser>(user, 'users', user.id);
Values are deep-cloned on the way in via structuredClone (since v1.1.0). Mutating your source object after set() does not affect the cached value. The only types set() cannot accept are functions, DOM nodes, and class instances with private fields — those throw UncloneableValueError. Plain objects, arrays, primitives, Date, Map, Set, typed arrays, etc. all clone cleanly.
Persistence note — if you enable persistence, values are also serialised to JSON on beforeunload. JSON is lossier than structuredClone (no Map, Set, Date, undefined), so anything that survives the in-memory clone but not the persistence round-trip will quietly degrade across reloads.
With a TTL
Add an ISetOptions object as the last argument:
this._cache.set('temporary', 'session', 'token', { ttl: 30000 }); // expires in 30 s
Full coverage in TTL & expiration.
Real-world example: caching HTTP responses (manual)
A common pattern is to wrap an HTTP call so the second invocation comes from the cache. For most cases you'll want cacheObservable() instead — it handles dedup, TTL and error fallbacks for you — but here's the manual version for reference:
import { HttpClient } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { Observable, of, tap } from 'rxjs';
import { NcachedService } from 'ng-ncached';
interface IUser {
email: string;
id: string;
name: string;
}
@Injectable({ providedIn: 'root' })
export class UserApi {
private readonly _cache = inject(NcachedService);
private readonly _http = inject(HttpClient);
getUser(id: string): Observable<IUser> {
const cached = this._cache.getOrDefault<IUser | null>(null, 'users', 'byId', id);
if (cached) {
return of(cached);
}
return this._http.get<IUser>(`/api/users/${id}`).pipe(
tap((user: IUser) => this._cache.set<IUser>(user, 'users', 'byId', id, { ttl: 60000 })),
);
}
}
Overwriting a value
Calling set() with the same key path replaces the existing entry, including resetting its TTL:
this._cache.set('v1', 'config', 'apiVersion', { ttl: 5000 });
this._cache.set('v2', 'config', 'apiVersion'); // overwrites; no TTL now
this._cache.get<string>('config', 'apiVersion'); // 'v2'
What's next?
- Getting values — read what you've stored, with type safety.
- TTL & expiration — make entries expire automatically.
- Nested namespaces — build deeper hierarchies.