@vgerbot/lazily is a tiny TypeScript utility for lazy initialization.
It lets you defer object creation until first use, then cache the result. You also get lifecycle helpers (onInitialized, invalidate, reset, etc.) for advanced control.
- Lazy object initialization through transparent proxy access
- Explicit
get()style lazy value access viavalue() - Initialization and invalidation lifecycle hooks
- Invalidate/reset cycle support for controlled re-creation
- Type-safe API designed for TypeScript
pnpm add @vgerbot/lazilyYou can also use npm or yarn:
npm i @vgerbot/lazily
# or
yarn add @vgerbot/lazilyimport { lazy, isInitialized } from '@vgerbot/lazily';
const config = lazy(() => {
console.log('creating config...');
return {
apiBaseUrl: 'https://api.example.com',
timeout: 5000,
};
});
console.log(isInitialized(config)); // false
// First property access initializes the object
console.log(config.apiBaseUrl); // logs "creating config..." then value
console.log(isInitialized(config)); // trueCreates a lazily-initialized proxy object.
factoryruns on first access only- The returned object is cached and reused
factorymust return a non-null object
import { lazy } from '@vgerbot/lazily';
const db = lazy(() => ({
connectedAt: Date.now(),
}));
// factory is called here
console.log(db.connectedAt);Creates a lazily-initialized value with explicit get() access.
import { value } from '@vgerbot/lazily';
const settings = value(() => ({ debug: true }));
const s = settings.get();
console.log(s.debug);Checks initialization state of a lazily instance.
import { lazy, isInitialized } from '@vgerbot/lazily';
const obj = lazy(() => ({ value: 1 }));
console.log(isInitialized(obj)); // false
console.log(obj.value); // initializes
console.log(isInitialized(obj)); // trueSubscribes to initialization.
- If already initialized, callback runs immediately
- Returns
unsubscribe()
import { lazy, onInitialized } from '@vgerbot/lazily';
const service = lazy(() => ({ ready: true }));
const unsubscribe = onInitialized(service, (real) => {
console.log('initialized:', real.ready);
});
service.ready; // triggers callback
unsubscribe();Subscribes to invalidation events.
import { lazy, onInvalidate, invalidate } from '@vgerbot/lazily';
const obj = lazy(() => ({ value: 42 }));
onInvalidate(obj, (real) => {
console.log('invalidated value:', real.value);
});
obj.value; // initialize first
invalidate(obj); // callback runsInvalidates a lazily instance.
- After invalidation, access throws until
reset()is called - No-op for non-lazily objects
import { lazy, invalidate } from '@vgerbot/lazily';
const obj = lazy(() => ({ value: 1 }));
obj.value;
invalidate(obj);
// obj.value now throws InvalidatedLazilyErrorResets a lazily instance to uninitialized state so it can be initialized again.
import { lazy, invalidate, reset } from '@vgerbot/lazily';
let count = 0;
const obj = lazy(() => ({ value: ++count }));
console.log(obj.value); // 1
invalidate(obj);
reset(obj);
console.log(obj.value); // 2Wires assignments so lazy fields are automatically replaced with real initialized values.
Useful for DI-like object assembly.
import { lazy, wire } from '@vgerbot/lazily';
const target: { service?: { value: number } } = {};
const service = lazy(() => ({ value: 100 }));
wire(target, function () {
this.service = service;
});
service.value; // initialize
// target.service is now the real initialized object@vgerbot/lazily exports strongly-typed error classes and codes:
LazilyErrorInvalidatedLazilyErrorNotLazilyInstanceErrorLazilyFactoryErrorInvalidFactoryReturnErrorLazilyErrorCode
Example:
import { LazilyError, LazilyErrorCode } from '@vgerbot/lazily';
try {
// your lazy logic
} catch (error) {
if (error instanceof LazilyError) {
if (error.code === LazilyErrorCode.INVALIDATED_ACCESS) {
// handle invalidated access
}
}
}lazy()andvalue()are object-oriented APIs; factories should return objects.onInitialized()andonInvalidate()throw if given a non-lazily instance.invalidate()is intentionally tolerant and does nothing for non-lazily values.
From repository root:
pnpm install
pnpm build
pnpm test
pnpm lint
pnpm typedocMIT