0

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'

Playground

Matthieu Riegler
  • 31,918
  • 20
  • 95
  • 134

0 Answers0