I have a Vue 3 project with typescript ( in the process of converting it from javascript to TS), no fancy plugins for vuex store, just simply typed it.
I have a mutation that is setting different properties of a order object, so I don't have to write a mutation for every property. Which looks like this in JS:
setMetaProp(state, { propName, value }) {
state.order[propName] = value;
}
Now, in my process of learning and converting stuff to TS i have written a function that can do this with type safety:
export interface PropNameKeyValue<KeyType, ValueType> {
propName: KeyType;
value: ValueType;
}
export declare function setMeta<Key extends keyof Order>(payload: PropNameKeyValue<Key, Order[Key]>): void;
//type of is_quote is boolean in the type declaration of type Order
setMeta({ propName: 'is_quote', value: '123' });
//if I try to set is_quote to something else than boolean here
// tsc catches the problem and complains that this should be a boolean
This is awesome and it works as it should be, but if i try to apply this to the mutation I have in the store, type safety is no more, the only thing it does that if i try to set a property that does not exist on type order, at least it tells me that that property does not exist on type Order.
Here is the code I have so far, I will include screenshots as well as to what it shows in the IDE when I hover over each function as well(not sure if it helps tho :)))):
// type declaration of mutations
export type Mutations < S = State > = {
[MutationTypes.setMetaProp] < PropName extends keyof Order > (
state: S,
payload: PropNameKeyValue < PropName, Order[PropName] >
): void;
};
// implementation
export const mutations: MutationTree < State > & Mutations = {
[MutationTypes.setMetaProp](state, {
propName,
value
}) { //i have tried not destructuring, did not change the outcome
state.order && (state.order[propName] = value);
},
};
// call the mutation:
commit(MutationTypes.setMetaProp, {
propName: 'is_quote',
value: '123'
}); // no complaints from tsc
//also type declaration of commit
commit < Key extends keyof Mutations, Params extends Parameters < Mutations[Key] > [1] > (
key: Key,
payload: Params
): ReturnType < Mutations[Key] > ;
So my question in the end is how can i solve this problem and have type safety?
(If i am here anyways, is there a way change this so i can give the dynamic Type to match the types on, as a type param(so i don't have to type out Order or any type if i have to use it in different places))
UPDATE: Typescript Playground link showcasing problem:
UPDATE2: A retarded solution...(specialCommit ?????):
Basically I declared another type of mutation into AugmentedActionContext and which works only for type Order (most retarded solution, but the only one I could think of)
Update3: In response to answer Playground So basically I would have different kinds of mutations, not only the ones I wanted to have work in the case of the question. Your answer shed some light on what is going on in the background, which i am grateful for. Maybe you have another idea? Or just should i do something like i had in my retarded solution? Basically my retarded solution is similar to yours, i found the problem with that params part just did not know why it did not work. But thank you for your explanation! Also my other problem with this solution is that it limits my usage to only one type for all of commits... Maybe i would like to set properties of a subObject of Order, this will eliminate that option as well.
My new question right now is, am i asking too much of TypeScript and Vuex combo??