Created
November 22, 2024 19:59
-
-
Save dvdotsenko/33c5b6ba6a88584255069894ac5c9430 to your computer and use it in GitHub Desktop.
TypeScript static initializer generic collection serialize / deserialize example with localStorage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface Serializable { | |
id: string | |
} | |
export interface SerializableStatic<T> { | |
new (data: Record<string, any>): T | |
} | |
export interface CollectionBase<T> { | |
add: (o: T) => void | |
get: (id: string) => T | null | |
values: () => Generator<T> | |
} | |
export class MemoryCollection<T> implements CollectionBase<T>{ | |
collection: Map<string, T> | |
constructor() { | |
this.collection = new Map<string, T>() | |
} | |
add(o: T) { | |
const id = (o as Serializable).id | |
this.collection.set(id, o) | |
} | |
get(id: string) { | |
return this.collection.get(id) || null | |
} | |
* values() { | |
let key: string | |
let value: T | |
for ([key, value] of this.collection) { | |
yield value | |
} | |
} | |
} | |
export class LocalStoreCollection<Tstat extends SerializableStatic<T>, T extends Serializable = InstanceType<Tstat>> implements CollectionBase<T>{ | |
namespace: string | |
instantiator: Tstat | |
constructor(instantiator: Tstat, namespace: string) { | |
this.namespace = namespace + '.' | |
this.instantiator = instantiator | |
} | |
add(o: T) { | |
const id = (o as Serializable).id | |
const key = this.namespace + id | |
const serialized = JSON.stringify(o) | |
localStorage.setItem(key, serialized) | |
} | |
_deserialize(dataStr: string): T { | |
const data: Record<string, unknown> = JSON.parse(dataStr); | |
return new this.instantiator(data) | |
} | |
get(id: string): T | null { | |
const key = this.namespace + id | |
const v = localStorage.getItem(key) | |
if (v) { | |
return this._deserialize(v) | |
} else { | |
return null | |
} | |
} | |
* values() { | |
let key: string | null | |
let i: number | |
let v_str: string | null | |
for (i = localStorage.length - 1; i >= 0; i--) { | |
key = localStorage.key(i) | |
if (key) { | |
if (key.startsWith(this.namespace)) { | |
v_str = localStorage.getItem(key) | |
if (v_str) { | |
yield this._deserialize(v_str) | |
} | |
} | |
} | |
} | |
} | |
} | |
export class MemoryCachedLocalStoreCollection<Tstat extends SerializableStatic<T>, T extends Serializable = InstanceType<Tstat>> implements CollectionBase<T>{ | |
memoryCollection: MemoryCollection<T> | |
localStoreCollection: LocalStoreCollection<Tstat, T> | |
constructor(instantiator: Tstat, namespace: string) { | |
this.localStoreCollection = new LocalStoreCollection(instantiator, namespace) | |
this.memoryCollection = new MemoryCollection<T>() | |
} | |
add(o: T) { | |
this.memoryCollection.add(o) | |
this.localStoreCollection.add(o) | |
} | |
get(id: string) { | |
let v = this.memoryCollection.get(id) | |
if (v) { | |
return v | |
} | |
v = this.localStoreCollection.get(id) | |
if (v) { | |
this.memoryCollection.add(v) | |
} | |
return v | |
} | |
* values() { | |
for (let v of this.localStoreCollection.values()) { | |
this.memoryCollection.add(v) | |
yield v | |
} | |
} | |
} | |
/////////////// usage ////////////// | |
interface ThingLike { | |
id?: string | |
name?: string | |
} | |
export class Thing implements Serializable { | |
id: string | |
name: string | |
constructor(o:ThingLike) { | |
this.id = o.id ? o.id : crypto.randomUUID() | |
this.name = o.name ? o.name : '' | |
} | |
} | |
const cc = new LocalStoreCollection(Thing, 'things') | |
const thing = new Thing({name:'Thing One'}) | |
cc.add(thing) | |
const thing_again: Thing | null = cc.get(thing.id) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A modification of https://dev.to/_staticvoid/defining-static-methods-in-interfaces-with-typescript-4232