vuex-smart-module
vuex-smart-module copied to clipboard
Return type of actions is Promise<unknown>
Hi @ktsn
I noticed that every return type of action method is considered as Promise<unknow>
. Even though if the action return type is Promise<SpecificType>
.
I think you did it on purpose, but I don't know how can I avoid the following error, I mean what is the best way to avoid it?
Whenever I return a Promise<SpecificType>, I get this kind of error:
TS2345: Argument of type '(response: AxiosResponse<any>) => void' is not assignable to parameter of type '(value: unknown) => void | PromiseLike<void>'.
I mean what is the best way to avoid it
Hi, normally, you shouldn't return a value from an action, preferring to put it in the store. Otherwise, you are going to lose the meaning of store as the single source of truth.
interface AnyNetworkData {
loading: boolean,
error: string | null,
data: ExampleDataType | null,
}
export class ExampleState {
anyNetworkData: AnyNetworkData = {
loading: false,
error: null,
data: null,
}
}
export class ExampleGetters extends Getters<ExampleState> {}
export class ExampleMutations extends Mutations<ExampleState> {
setAnyNetworkData(payload: AnyNetworkData): void {
this.state.anyNetworkData = { ...payload };
}
}
export class ExampleActions extends Actions<
ExampleState,
ExampleGetters,
ExampleMutations,
ExampleActions
> {
async fetch(): Promise<void> {
this.mutations.setAnyNetworkData({ loading: true, error: null, data: null });
try {
const response = await ApiClient.doSomething();
this.mutations.setAnyNetworkData({ loading: false, error: null, data: response.data });
} catch ({ message }) {
this.mutations.setAnyNetworkData({ loading: false, error: message, data: null });
}
}
}
First i wanna thank you for great module, it really cool!
Return type for action promise can be very usefully:
Example 1
interface Item {
id: number | null;
name :string;
}
export interface Raw {
// eslint-disable-next-line
[key: string]: any;
}
const parseItem = (data: Raw): Item => ({
id: data['id'] ? Number(data['id']) : null,
name: String(data['name']),
})
export class ExampleActions extends Actions<
ExampleState,
ExampleGetters,
ExampleMutations,
ExampleActions
> {
createItem(item: Item): Promise<Item> {
return api.create(item)
.then(({ data }) => {
const newItem = parseItem(data.data);
this.mutations.setItem(newItem);
return newItem;
})
}
}
In component:
onSave(): void {
this.exampleStore.actions.createItem(item)
.then((item: Item) => {
// here I can use the item without access to store
// Without item, I would not have been able to find it in a store as I did not know its id before creating it.
this.activeItem = item;
})
}
Example 2
export class ExampleActions extends Actions<
ExampleState,
ExampleGetters,
ExampleMutations,
ExampleActions
> {
/**
* Check item in store before load it.
* This is useful to avoid unnecessary requests to the api and reuse of logic in different components.
*
* @param itemId
*/
loadItem(itemId: number): Promise<Item> {
return this.state.items[itemId]
? Promise.resolve(this.state.items[itemId])
: api.loadItem(itemId)
.then(({ data }) => {
const newItem = parseItem(data.data);
this.mutations.setItem(newItem);
return newItem;
})
}
}