michaelolof / vuex-class-component

A Type Safe Vuex Module or Store Using ES6 Classes and ES7 Decorators written in TypeScript.
217 stars 21 forks source link

Getter with method arguments #19

Closed hdt80 closed 5 years ago

hdt80 commented 5 years ago

Sorry if this is the wrong place for this.

When converting an existing Vuex store, I used getters that accepted arguments, and I am not able to figure out how to do this using a VuexModule instead.

Here is an example of the existing code I am converting:

export const store = new Vuex.Store({
    state: {
        users: new Map() as Map<number, Promise<User | null>>,
    },

    getters: {
        user: (state) => (userID: number): Promise<User | null> => {
            return Promise.resolve(null); // Example code
        },
    }
});

I would use this getter by calling this.$store.getter.user(42) for example.

Here is what I've tried when converting to use VuexModule instead:

@Modue()
export class UserStore extends VuexModule {
    private users: Map<number, Promise<User | null>> = new Map();

    // Causes "TypeError: this.store.user is not a function"
    // Inspecting what "this.store" contains, I can see that "this.store.user" is undefined
    @getter user(userID: number): Promise<User | null> {
        return Promise.resolve(null);
    }

    // Same error as above
    @getter public user(userID: number): Promise<User | null> {
        return Promise.resolve(null);
    }

    // Same error as above
    public user(userID: number): Promise<User | null> {
        return Promise.resolve(null);
    }

    // Suggestion from issue #7 
    // Throws a Typescript error when compiling: "(TS) A 'get' accessor cannot have parameters"
    get user(userID: number): Promise<User | null> {
        return Promise.resolve(null);
    }
}

The VuexModule is created by calling:

data: function() {
    return {
        store: UserStore.CreateProxy(this.$store, UserStore);
    }
}

Is this functionality possible in vuex-class-component? Let me know if I didn't make something clear enough or you need additional information to help me. Thank you!

asmadsen commented 5 years ago

The concept of getters should usually (as far as I know) not take any arguments. So vuex getters should in my opinion be treated the same way you would treat an computed property in a Vue Component.

I totally understand where you are coming from and I see the need to have this feature, but I would recommend using an action for this. Because it has access to the state as well, and could be used to do the same calculation and just returning the result without manipulating the state.

hdt80 commented 5 years ago

@asmadsen Vuex officially supports this and provides and example on their site.

https://vuex.vuejs.org/guide/getters.html#method-style-access

hdt80 commented 5 years ago

A possible way to solve this is instead of returning a value, return a function.

For example:

@getter user: (userID: number) => Promise<User | null> = (userID: number) => Promise<User | null> {
    return Promise.resolve(null);
}

// Usage:
this.store.user(42);

This seems like it's not the intended way to use a getter method style access, but it is a work around in the meantime.

michaelolof commented 5 years ago

Have you tried doing something like this

 get user() {
   return (userId) => {
     return Prosime.resolve( null )
   }
 }
michaelolof commented 5 years ago

I'm not with my laptop now so can't test.

get user() => (userId) => {
  return Promise.resolve( true )
}

Not sure of this though.

Or this

@getter user = (userId) => Promise.resolve( true )
hdt80 commented 5 years ago

Reading their example of the method style access more carefully, they say you return a function from the getter:

You can also pass arguments to getters by returning a function. (https://vuex.vuejs.org/guide/getters.html#method-style-access)

So looks like that way is the officially supported way to use a getter with parameters. Thank you for helping me figure this out! Would you mind if a created a PR adding an example of a getter with parameters for future users?