Search code examples
reactjstypescriptmobxmobx-react

Dynamic state update in mobx react typescript


I want to have a function that accepts only the state declared in mobx. I currently have this code.

class DialogStore {
    status: boolean = false;
    title: string = '';
    content: string = '';
    btnText: string = ''; 
    icon: JSX.Element | string = '';
    type: 'success' | 'error' = 'success';

    constructor() {
        makeAutoObservable(this);
    }

    toggle(status: boolean) {
        this.status = status
    }

    success(content: string) {
        this.type = 'success';
        this.status = true;
        this.content = content;
    }

    error(content: string) {
        this.type = 'error';
        this.status = true;
        this.content = content;
    }
}

I want to add a dynamic function like this:

update(payload: TypeOfState) {
    Object.keys(payload).forEach(property => {
        this[property] = payload[property];
    })
}

I tried to place any as my payload type but it gives me this error Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'DialogStore'. I want the payload to only accept the state I declared at the top.


Solution

  • If I understand you correctly you want to have single function instead of toggle, success and error?

    Would something like this work for your case?

    class DialogStore {
      // ...
    
      update(payload: StateToUpdate) {
        Object.keys(payload).forEach((property) => {
          this[property] = payload[property];
        });
      }
    }
    
    type StateToUpdate = Partial<Pick<DialogStore, 'status' | 'type' | 'content'>>
    
    

    To avoid TS error you could disable flag "suppressImplicitAnyIndexErrors": true altogether in your tsconfig.json or use some typecasting:

        Object.keys(payload).forEach((property) => {
          (this as any)[property] = payload[property as keyof StateToUpdate];
        });
    

    I think there is no easy way to mitigate this type of error in TS right now, I might be wrong though.