quarrant / mobx-persist-store

Persist and rehydrate observable properties in mobx store.
268 stars 14 forks source link

MakePersistable can't get the private propertys in mobx store #79

Closed PuffMeow closed 2 years ago

PuffMeow commented 2 years ago

Below is the code


class Store {
  constructor() {
    makeAutoObservable(this);
    makePersistable(this, {
      name: 'Store',
     // This is an error: "Type 'string' is not assignable to type 'keyof this'.  Type '"state"' is not assignable to type 'keyof Store'.ts"
      properties: ['state'],
      storage: window.localStorage,
    });
  }

 // ------------ See this, I added a private preffix------------
  private state = DEFAULT_STATE;

  getState(path: string | number) {
    return get(this.state, path);
  }

  setState(key: string, val: unknown) {
    set(this.state, key, val);
  }
}

export default Store;
PuffMeow commented 2 years ago

The private properties can't be accessed by outside of the library. But I think the makePersistable API should provide a way to get the private state. Like this:

class Store {
  constructor() {
    makeAutoObservable(this);
    makePersistable(this, {
      name: 'Store',
     // ++++++++++
      properties: [getAllState],
      storage: window.localStorage,
    });
  }

  private state = DEFAULT_STATE;

 // ++++++++ 
  getAllState() {
    return this.state;
  }
}

export default Store;
quarrant commented 2 years ago

Hey

Honestly I didn't think about it. It's interesting... I will try to find solution

codeBelt commented 2 years ago

Hmmm, not sure how to fix that.

It makes sense since makePersistable is trying to validate that 'state' is a property on the Store but TypeScript is stating makePersistable shouldn't have access to private properties. It's more of a TypeScript issue than makePersistable. It still works when you run the code but the compiler is complaining.

quarrant commented 2 years ago

Nope. The property labeled private doesn't excluded from watched properties, because makePersistable works inside the class and has access to the all properties.

I'm not sure, but I think @JiquanWang99 have a problem with understanding how it works. makePersistable couldn't watch computed or action properties, it works only with observable properties.

Anyway, let me know what is your version mobx-persist-store and what is the DEFAULT_STATE

PuffMeow commented 2 years ago

The version mox-persist-store in my project is "^1.0.6", and the DEFAULT_STATE is

export const DEFAULT_STATE = {
  username: 'defaultUser',
  role: 3,
};

And this is working for me, but when I add a private preffix before the state, it doesn't work anymore.

class Store {
  constructor() {
    makeAutoObservable(this);
    makePersistable(this, {
      name: 'Store',
      properties: ['state'],
      storage: window.localStorage,
    });
  }

  state = DEFAULT_STATE;

  getState(path: string | number) {
    return get(this.state, path);
  }

  setState(key: string, val: unknown) {
    set(this.state, key, val);
  }
}
PuffMeow commented 2 years ago

@codeBelt You are right, what you said is my problem.

quarrant commented 2 years ago

@JiquanWang99 So... I wrote a small example with private state and it has worked (example). Anyway could you show me a full code?

PuffMeow commented 2 years ago

@quarrant It can work but TypeScript still has a complain when compling...

quarrant commented 2 years ago

@JiquanWang99

I just didn't spend a time for the right types. Unfortunately, I don't have any idea how I can infer private type from a class because it's not a enumerable.

Anyway, you may use @ts-ignore and define public accessor to the private state. I'm sure It helps.

class Store {
  constructor() {
    makeAutoObservable(this);
    makePersistable(this, {
      name: "Store",
      // @ts-ignore
      properties: ["_state"],
      storage: window.localStorage
    });
  }

  private _state = DEFAULT_STATE;

  public get state() {
    return this._state
  }

  ...

}
PuffMeow commented 2 years ago

@quarrant Thanks, that's OK.

stberger3040 commented 2 years ago

I just didn't spend a time for the right types. Unfortunately, I don't have any idea how I can infer private type from a class because it's not a enumerable.

In mobx package (e.g. makeObservable), they solved it by letting the user pass additional properties, if they are private, see https://github.com/mobxjs/mobx/blob/main/packages/mobx/src/api/makeObservable.ts#L26

quarrant commented 2 years ago

@stberger3040 It's not a solution to access to private properties in the object.