A library for defining lazily evaluated properties and variables powered by TypeScript.
@vgerbot/lazy
is a useful tool for managing lazy evaluation properties.
It defers expensive property(or a variable) initialization until needed and avoids unnecessary repeated evaluation.
This library supports adding reset tester for lazy properties, once the reset tester detects a change, the property will be re-evaluated and initialized the next time the property is accessed, which simplifies a lot of work
npm i @vgerbot/lazy
Requires the
compilerOptions.experimentalDecorators
intsconfig.json
to be set totrue
import { lazyMember } from '@vgerbot/lazy';
function getFriends(id: string, params: Record<string, string | number> = {}): Promise<User[]> {
const url = new URL('http://api.domain.com/friends');
url.searchParams.append('userId', id);
for(const key in params) {
url.searchParams.append(key, params[key]);
}
console.log('fetch: ',url);
return fetch(url)
.then(resp => {
return resp.json()
})
.then(data => userListOf(data));
}
class User {
@lazyMember<User, 'friends'>(user => getFriends(user.id))
friends!: Promise<User[]>;
@lazyMember<User, 'littleBrothers'>({
evaluate: user => getFriends(user.id, {maxAge: user.age}),
resetBy: ['age']
})
littleBrothers!: Promise<User[]>;
constructor(readonly id: string, age: number) {
}
}
With the lazy properties ready, we can now use it:
const user = new User('a5cba8f', 18)
user.friends.then(() => {
})
// console output: "fetch: http://api.domain.com/friends?userId=a5cba8f"
user.friends.then(() => {
}) // nothing output
user.littleBrothers.then(() => {
})
// console output: "fetch: http://api.domain.com/friends?userId=a5cba8f&maxAge=18"
user.littleBrothers.then(() => {
})
// nothing is output
user.age = 19;
// The `age` property has changed, so the `littleBrothers` property will also be reset.
user.littleBrothers.then(() => {
})
// console output: "fetch: http://api.domain.com/friends?userId=a5cba8f&maxAge=<b>19</b>"
If you don't like or can't use decorators, you can do this:
import { lazyMemberOfClass } from '@vgerbot/lazy';
class User {
friends!: Promise<User[]>;
littleBrothers!: Promise<User[]>;
constructor(readonly id: string, age: number) {
}
}
lazyMemberOfClass(User, 'friends', (user) => getFriends(user.id));
lazyMemberOfClass(User, 'littleBrothers', {
evaluate: user => getFriends(user.id, {maxAge: user.age}),
resetBy: ['age']
});
The rest is the same as the appeal '@lazyMember', so I won't repeat it here.
Define lazily evaluated property on an object:
import { lazyProp } from '@vgerbot/lazy';
const giraffe = {} as { rainbow: string };
lazyProp(object, 'rainbow', () => expansiveComputation());
console.log(giraffe.rainbow);
Create a lazily evaluated value:
import { lazyVal } from '@vgerbot/lazy';
const value = lazyVal(() => expensiveComputation());
button.onclick = () => {
doSomthing(value.get());
};
For more usage, see the unit test code.
License under the MIT Licensed (MIT)