This module encapsulates the following common initialization-at-first-usage pattern:
class MyClass {
private _element: null | HTMLDivElement;
private _initElement() {
this._element = /* ... do whatever it takes to get this ready... */;
}
methodWhichNeedsElement() {
if (this._element === null) {
this._initElement();
}
// use this._element somehow...
console.log(this._element!.innerText);
}
anotherMethodWhichNeedsElement() {
if (this._element === null) {
this._initElement();
}
// use this._element somehow...
console.log(this._element!.innerText);
}
aThirdMethodWhichNeedsElement() {
if (this._element === null) {
this._initElement();
}
// use this._element somehow...
console.log(this._element!.innerText);
}
}into this:
import { deferredInit } from "@suchipi/deferred-init";
class MyClass {
private _deferredVars = deferredInit({
element: () => {
const element = /* ... do whatever it takes to get this ready... */;
return element;
}
})
methodWhichNeedsElement() {
// use this._deferredVars.element somehow...
console.log(this._deferredVars.element.innerText);
}
anotherMethodWhichNeedsElement() {
// use this._deferredVars.element somehow...
console.log(this._deferredVars.element.innerText);
}
aThirdMethodWhichNeedsElement() {
// use this._deferredVars.element somehow...
console.log(this._deferredVars.element.innerText);
}
}NOTE: This example uses DOM APIs, but the library works with any value, and doesn't itself depend on any DOM APIs.
Given a mapping object of name-to-init-functions, create an object with the same property keys, whose property descriptors are initially getters which run the initializer function for that key and then replace the getter descriptor with a standard value descriptor.
The net effect is that the first time you read a given key, its initializer function is run to get a resulting value, and on subsequent reads, that resulting value is re-used, without running the initializer function.
@paraminitializers — A object whose keys are arbitrary (your choice) and whose values are functions assignable to the type() => any, where the returnedanytype is the initialized value. The values are considered "initializer functions" which get used the first time the corresponding key is read on the object returned by deferredInit.@returnsAn object with the same keys as the initializers object passed in, which run the initializer function on the first read and re-use the result on later calls.
declare function deferredInit<
Initializers extends {
[Key: PropertyKey]: () => any;
},
>(
initializers: Initializers
): { readonly [Key in keyof Initializers]: ReturnType<Initializers[Key]> };Peek into an object returned by deferredInit and check if one of its properties has been initialized, without causing initialization to occur.
@paramdeferredInitResult — The object returned from deferredInit@paramkey — The key on the object which you want to check the initialization status of@returnsA boolean indicating whether that key has been initialized yet.
declare function isInitialized<
DeferredInitResult extends {
[Key: PropertyKey]: any;
},
>(
deferredInitResult: DeferredInitResult,
key: keyof DeferredInitResult
): boolean;MIT