Skip to content

Instantly share code, notes, and snippets.

@netcall-jlo
Last active February 2, 2024 10:59
Show Gist options
  • Save netcall-jlo/a083128f130a6f286b3fee8304dfa00b to your computer and use it in GitHub Desktop.
Save netcall-jlo/a083128f130a6f286b3fee8304dfa00b to your computer and use it in GitHub Desktop.
Playing with a type-safe cache
export class Cache<
TLookupMap extends Record<string, any> = {},
K extends keyof TLookupMap = keyof TLookupMap
> {
private key: string;
private storage: Record<K, TLookupMap[K]>;
constructor(key: string) {
this.key = key;
this.storage = (
window.localStorage.getItem(key)
|| Object.create(null)
);
}
processLookups(lookups: Record<K, (resolve: (data: TLookupMap[K]) => void) => void>) {
const {
storage
} = this;
return Promise.all(
Object
.entries(lookups)
.map(([key, lookup]) => this.convertLookup(
key as K,
lookup as (resolve: (data: TLookupMap[K]) => void) => void
))
).then((entries) => {
return Object.fromEntries(entries as Iterable<[K, TLookupMap[K]]>) as TLookupMap;
});
}
convertLookup(key: K, lookup: (resolve: (data: TLookupMap[K]) => void) => void) {
const {
storage
} = this;
return new Promise<[K, TLookupMap[K]]>((resolve) => {
// if (Object.hasOwn(this.storage, key)) {
if (Object.prototype.hasOwnProperty.call(storage, key)) {
return resolve([key, storage[key]]);
}
lookup((data) => {
storage[key] = data;
this.writeStorage();
resolve([key, data]);
});
});
}
writeStorage() {
window.localStorage.setItem(this.key, JSON.stringify(this.storage));
}
}
const cache = new Cache<{
roles: any[],
info: string[]
}>("my-cache");
cache.processLookups({
// TypeScript not yet type-safe
// `(parameter) resolve: (data: any[] | string[]) => void`
// Preferred solution: `(parameter) resolve: (data: any[]) => void`
// because TLookupMap[roles] gives any[]
roles(resolve) {
fetch("/path/to/roles")
.then((response) => response.json())
.then((json) => resolve(json));
},
info(resolve) {
resolve([]);
}
}).then((data) => {
(window as any).repositoryModel.setRoles(data.roles);
(window as any).infoModel.setInfos(data.info);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment