Search code examples
javascripttypescriptlocal-storagegetter-setter

How to generate getters and setters in Javascript?


I have the following code, which is very repetitious:

const flags = {
  get logged() {
    return localStorage.getItem("logged") === "true";
  },
  set logged(val: boolean) {
    if (val) {
      localStorage.setItem("logged", "true");
    } else {
      localStorage.removeItem("logged");
    }
  },
  get notificationsMuted() {
    return localStorage.getItem("notifications-muted") === "true"; 
  },
  set notificationsMuted(val: boolean) {
    if (val) {
      localStorage.setItem("notifications-muted", "true");
    } else {
      localStorage.removeItem("notifications-muted");
    }
  }
}

As you can see, the get and set for each flag type is identical, save for the property names. I would like to do something like this instead:

function getter(prop: string) {
  return localStorage.getItem(prop) === "true";
}

function setter(prop: string, val: boolean) {
  if (val) {
    localStorage.setItem(prop, "true");
  } else {
    localStorage.removeItem(prop);
  }
}

const flags = {
  get logged: getter("logged")
  set logged: setter("logged")
  get notificationsMuted: getter("notifications-muted")
  set notificationsMuted: setter("notifications-muted")
}

But I'm not sure if Javascript / Typescript has support for this sort of thing. Is such a thing possible, and if so, how? If not, is there any other way I can cut down on the repetition here?


Solution

  • You can use a proxy with get and set traps, use TS types to allow only props you wish to handle (TS playground)):

    interface Flags {
      logged: boolean,
      'notifications-muted': boolean;
    }
    
    type Prop = keyof Flags;
    
    const handlers = {
      get(_: Flags, prop: Prop) {   
        return localStorage.getItem(prop) === "true";
      },
      
      set(_: Flags, prop: Prop, val: any) {
        if (val) {
          localStorage.setItem(prop, "true");
        } else {
          localStorage.removeItem(prop);
        }
    
        return true;
      }
    };
    
    const flags = new Proxy<Flags>({} as Flags, handlers);