I've written this decorator which uses a Proxy to read value from the local storage for a list of specified properties.
function StoredValues<T>(storageKey: string, storedProperties: Array<keyof T>) {
function keyForProperty(property: string | symbol) {
return `${storageKey}.${property.toString()}`;
}
function shouldUseStorage(property: string | symbol): boolean {
return storedProperties.includes(property as keyof T); // Is it possible without type assertion ?
}
function actualDecorator(target: Function) {
// better return type ?
const f: any = function (...args: any[]) {
return new Proxy(Reflect.construct(target, args), {
get(target, property) {
if (shouldUseStorage(property)) {
const fromStorage = localStorage.getItem(keyForProperty(property));
if (fromStorage) {
console.log('From storage', fromStorage);
// Warning !!! this will return a string (was number before)
return fromStorage;
}
}
console.log('Pass through', property);
return target[property];
},
set(target: any, property: string | symbol, value: any): boolean {
target[property] = value;
if (shouldUseStorage(property)) {
localStorage.setItem(keyForProperty(property), value);
}
console.log('Set', property, 'to', value);
return true;
},
});
};
return f;
}
return actualDecorator;
}
I'm not quite satisfied with the typing I've used, particularly the any
as return type. I've tried multiple things but I can't get quite the right typing.
For example if I use new Proxy<T>()
, the compiler returns Decorator function return type '(...args: any[]) => Bar' is not assignable to type 'void | typeof Bar'