Skip to content

Commit 0972c15

Browse files
committed
Use function overloads for accessors without payload. Rename types.
1 parent 19ff43b commit 0972c15

File tree

9 files changed

+100
-187
lines changed

9 files changed

+100
-187
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vuex-typescript",
3-
"version": "0.0.6",
3+
"version": "0.1.0",
44
"description": "A simple way to get static typing, static code analysis and intellisense with Vuex library.",
55
"files": [
66
"dist/index.js",

src/index.ts

Lines changed: 88 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,98 @@ export function Handler(target: any, key: string) {
66
target[key]._vuexKey = key;
77
}
88

9-
export type MutationHandler<TModuleState, TPayload> =
10-
(state: TModuleState, payload: TPayload) => void;
11-
export type PayloadlessMutationHandler<TModuleState> =
12-
(state: TModuleState) => void;
9+
/**
10+
* Vuex getter handler specified in Vuex options.
11+
*/
12+
export type GetterHandler<TModuleState, TRootState, TResult> =
13+
(state: TModuleState, rootState: TRootState) => TResult;
1314

14-
export type ActionHandler<TModuleState, TRootState, TPayload, TResult> =
15+
/**
16+
* Vuex action handler which takes payload as specified in Vuex options.
17+
*/
18+
export type ActionHandlerWithPayload<TModuleState, TRootState, TPayload, TResult> =
1519
(injectee: ActionContext<TModuleState, TRootState>, payload: TPayload) => void | Promise<TResult>;
16-
export type PayloadlessActionHandler<TModuleState, TRootState, TResult> =
20+
/**
21+
* Vuex action handler which does not take payload as specified in Vuex options.
22+
*/
23+
export type ActionHandlerNoPayload<TModuleState, TRootState, TResult> =
1724
(injectee: ActionContext<TModuleState, TRootState>) => void | Promise<TResult>;
1825

19-
export type GetterHandler<TModuleState, TRootState, TResult> =
20-
(state: TModuleState, rootState: TRootState) => TResult;
26+
/**
27+
* Vuex mutation handler which takes payload as specified in Vuex options.
28+
*/
29+
export type MutationHandlerWithPayload<TModuleState, TPayload> =
30+
(state: TModuleState, payload: TPayload) => void;
31+
/**
32+
* Vuex mutation handler which does not take payload as specified in Vuex options.
33+
*/
34+
export type MutationHandlerNoPayload<TModuleState> =
35+
(state: TModuleState) => void;
2136

37+
/**
38+
* Function which gets value of a concrete Vuex getter.
39+
*/
2240
export type GetAccessor<TModuleState, TRootState, TResult> =
2341
(store: Store<TRootState> | ActionContext<TModuleState, TRootState>) => TResult;
2442

25-
export type DispatchAccessor<TModuleState, TRootState, TPayload, TResult> =
43+
/**
44+
* Function which dispatches a concrete Vuex action with payload.
45+
*/
46+
export type DispatchAccessorWithPayload<TModuleState, TRootState, TPayload, TResult> =
2647
(store: Store<TRootState> | ActionContext<TModuleState, TRootState>,
2748
payload: TPayload) => Promise<TResult>;
28-
export type PayloadlessDispatchAccessor<TModuleState, TRootState, TResult> =
49+
/**
50+
* Function which dispatches a concrete Vuex action without payload.
51+
*/
52+
export type DispatchAccessorNoPayload<TModuleState, TRootState, TResult> =
2953
(store: Store<TRootState> | ActionContext<TModuleState, TRootState>) => Promise<TResult>;
3054

31-
export type CommitAccessor<TModuleState, TRootState, TPayload> =
55+
/**
56+
* Function which commits a concrete Vuex mutation with payload.
57+
*/
58+
export type CommitAccessorWithPayload<TModuleState, TRootState, TPayload> =
3259
(store: Store<TRootState> | ActionContext<TModuleState, TRootState>,
3360
payload: TPayload) => void;
34-
export type PayloadlessCommitAccessor<TModuleState, TRootState> =
61+
/**
62+
* Function which commits a concrete Vuex mutation without payload.
63+
*/
64+
export type CommitAccessorNoPayload<TModuleState, TRootState> =
3565
(store: Store<TRootState> | ActionContext<TModuleState, TRootState>) => void;
3666

3767
export interface StoreAccessors<TModuleState, TRootState> {
68+
/**
69+
* Returns a function committing mutations directed to the specified mutation handler.
70+
* This overload is for handlers which do not expect payload.
71+
*/
72+
commit(
73+
handler: MutationHandlerNoPayload<TModuleState>):
74+
CommitAccessorNoPayload<TModuleState, TRootState>;
75+
/**
76+
* Returns a function committing mutations directed to the specified mutation handler.
77+
* This overload is for handlers which expect payload.
78+
*/
3879
commit<TPayload>(
39-
handler: MutationHandler<TModuleState, TPayload>):
40-
CommitAccessor<TModuleState, TRootState, TPayload>;
41-
commitNoPayload(
42-
handler: PayloadlessMutationHandler<TModuleState>):
43-
PayloadlessCommitAccessor<TModuleState, TRootState>;
44-
80+
handler: MutationHandlerWithPayload<TModuleState, TPayload>):
81+
CommitAccessorWithPayload<TModuleState, TRootState, TPayload>;
82+
83+
/**
84+
* Returns a function dispatching actions directed to the specified action handler.
85+
* This overload is for handlers which do not expect payload.
86+
*/
87+
dispatch<TResult>(
88+
handler: ActionHandlerNoPayload<TModuleState, TRootState, TResult>):
89+
DispatchAccessorNoPayload<TModuleState, TRootState, TResult>;
90+
/**
91+
* Returns a function dispatching actions directed to the specified action handler.
92+
* This overload is for handlers which expect payload.
93+
*/
4594
dispatch<TPayload, TResult>(
46-
handler: ActionHandler<TModuleState, TRootState, TPayload, TResult>):
47-
DispatchAccessor<TModuleState, TRootState, TPayload, TResult>;
48-
dispatchNoPayload<TResult>(
49-
handler: PayloadlessActionHandler<TModuleState, TRootState, TResult>):
50-
PayloadlessDispatchAccessor<TModuleState, TRootState, TResult>;
95+
handler: ActionHandlerWithPayload<TModuleState, TRootState, TPayload, TResult>):
96+
DispatchAccessorWithPayload<TModuleState, TRootState, TPayload, TResult>;
5197

98+
/**
99+
* Returns a function returning value of the specified getter.
100+
*/
52101
read<TResult>(
53102
handler: GetterHandler<TModuleState, TRootState, TResult>):
54103
GetAccessor<TModuleState, TRootState, TResult>;
@@ -57,64 +106,26 @@ export interface StoreAccessors<TModuleState, TRootState> {
57106
export function getStoreAccessors<TModuleState, TRootState>(
58107
namespace: string): StoreAccessors<TModuleState, TRootState> {
59108
return {
60-
commit: <TPayload>(handler: MutationHandler<TModuleState, TPayload>) =>
61-
commit(handler, namespace),
62-
commitNoPayload: (handler: PayloadlessMutationHandler<TModuleState>) =>
63-
commitNoPayload(handler, namespace),
64-
65-
dispatch: <TPayload, TResult>(handler: ActionHandler<TModuleState, TRootState, TPayload, TResult>) =>
66-
dispatch(handler, namespace),
67-
dispatchNoPayload: <TResult>(handler: PayloadlessActionHandler<TModuleState, TRootState, TResult>) =>
68-
dispatchNoPayload(handler, namespace),
69-
read: <TResult>(handler: GetterHandler<TModuleState, TRootState, TResult>) =>
70-
read(handler, namespace),
71-
};
72-
}
73-
74-
function read<TModuleState, TRootState, TResult>(
75-
handler: GetterHandler<TModuleState, TRootState, TResult>,
76-
namespace: string): GetAccessor<TModuleState, TRootState, TResult> {
77-
const key = qualifyKey(handler, namespace);
78-
return (store: any) => {
79-
return store.rootGetters
80-
? <TResult>store.rootGetters[key] // ActionContext
81-
: <TResult>store.getters[key]; // Store
82-
};
83-
}
84-
85-
function dispatch<TModuleState, TRootState, TPayload, TResult>(
86-
handler: ActionHandler<TModuleState, TRootState, TPayload, TResult>,
87-
namespace: string): DispatchAccessor<TModuleState, TRootState, TPayload, TResult> {
88-
const key = qualifyKey(handler, namespace);
89-
return (store, payload) => {
90-
return <any>store.dispatch(key, payload, useRootNamespace);
91-
};
92-
}
93-
94-
function dispatchNoPayload<TModuleState, TRootState, TResult>(
95-
handler: PayloadlessActionHandler<TModuleState, TRootState, TResult>,
96-
namespace: string): PayloadlessDispatchAccessor<TModuleState, TRootState, TResult> {
97-
const key = qualifyKey(handler, namespace);
98-
return (store) => {
99-
return <any>store.dispatch(key, undefined, useRootNamespace);
100-
};
101-
}
102-
103-
function commit<TModuleState, TRootState, TPayload>(
104-
handler: MutationHandler<TModuleState, TPayload>,
105-
namespace: string): CommitAccessor<TModuleState, TRootState, TPayload> {
106-
const key = qualifyKey(handler, namespace);
107-
return (store, payload) => {
108-
store.commit(key, payload, useRootNamespace);
109+
commit: (handler: Function) => createAccessor("commit", handler, namespace),
110+
dispatch: (handler: Function) => createAccessor("dispatch", handler, namespace),
111+
read: (handler: Function) => {
112+
const key = qualifyKey(handler, namespace);
113+
return (store: any) => {
114+
return store.rootGetters
115+
? store.rootGetters[key] // ActionContext
116+
: store.getters[key]; // Store
117+
};
118+
},
109119
};
110120
}
111121

112-
function commitNoPayload<TModuleState, TRootState>(
113-
handler: PayloadlessMutationHandler<TModuleState>,
114-
namespace: string): PayloadlessCommitAccessor<TModuleState, TRootState> {
122+
function createAccessor(
123+
operation: string,
124+
handler: Function,
125+
namespace: string): any {
115126
const key = qualifyKey(handler, namespace);
116-
return (store) => {
117-
store.commit(key, undefined, useRootNamespace);
127+
return (store: any, payload: any) => {
128+
return store[operation](key, payload, useRootNamespace);
118129
};
119130
}
120131

src/tests/withModules/actions.spec.ts

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,31 +29,7 @@ describe("Given store with modules exposing actions", () => {
2929
+ "built with dispatch function", () => {
3030

3131
beforeEach(async () => {
32-
await basket.dispatchSelectAvailableItems(store, {});
33-
});
34-
35-
it("mutates state of the module via mutations invoked within the action", () => {
36-
expect(store.state).to.deep.equal({
37-
system: {
38-
userLogin: "abc",
39-
},
40-
basket: {
41-
items: [
42-
{ product: { id: 1, name: "clock", unitPrice: 50 }, isSelected: true },
43-
{ product: { id: 2, name: "newspaper", unitPrice: 20 }, isSelected: true },
44-
{ product: { id: 3, name: "candy", unitPrice: 10 }, isSelected: true },
45-
],
46-
totalAmount: 80,
47-
},
48-
});
49-
});
50-
});
51-
52-
describe("when parameterless action is dispatched in a module using function "
53-
+ "built with dispatchNoPayload function", () => {
54-
55-
beforeEach(async () => {
56-
await basket.dispatchSelectAvailableItems2(store);
32+
await basket.dispatchSelectAvailableItems(store);
5733
});
5834

5935
it("mutates state of the module via mutations invoked within the action", () => {

src/tests/withModules/mutations.spec.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,7 @@ describe("Given store with modules exposing mutations", () => {
2323

2424
describe("when parameterless mutation is made in a module using function built with commit function", () => {
2525
beforeEach(() => {
26-
basket.commitReset1(store, {});
27-
});
28-
29-
it("mutates state of the module and not state of other modules", () => {
30-
expect(store.state).to.deep.equal({
31-
system: {
32-
userLogin: "abc",
33-
},
34-
basket: {
35-
items: [],
36-
totalAmount: 0,
37-
},
38-
});
39-
});
40-
});
41-
42-
describe("when parameterless mutation is made in a module using function built "
43-
+ "with commitNoPayload function", () => {
44-
beforeEach(() => {
45-
basket.commitReset2(store);
26+
basket.commitReset(store);
4627
});
4728

4829
it("mutates state of the module and not state of other modules", () => {

src/tests/withModules/store/basket/basket.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ export const basket = {
7070
},
7171

7272
async SelectAvailablieItemsAndUpdateTotalAmount(context: BasketContext, discount: number): Promise<void> {
73-
await dispatchSelectAvailableItems2(context);
73+
await dispatchSelectAvailableItems(context);
7474
await dispatchUpdateTotalAmount(context, discount);
7575
},
7676
},
7777
};
7878

79-
const { commit, commitNoPayload, read, dispatch, dispatchNoPayload } =
79+
const { commit, read, dispatch } =
8080
getStoreAccessors<BasketState, RootState>("basket");
8181

8282
const getters = basket.getters;
@@ -88,19 +88,13 @@ export const readTotalAmountWithoutDiscount = read(getters.getTotalAmountWithout
8888
const actions = basket.actions;
8989

9090
export const dispatchUpdateTotalAmount = dispatch(actions.updateTotalAmount);
91-
// Variant 1: simpler but yelding worse API:
9291
export const dispatchSelectAvailableItems = dispatch(actions.selectAvailableItems);
93-
// Variant 2: a bit more complex but yelding better API:
94-
export const dispatchSelectAvailableItems2 = dispatchNoPayload(actions.selectAvailableItems);
9592
export const dispatchSelectAvailablieItemsAndUpdateTotalAmount =
9693
dispatch(actions.SelectAvailablieItemsAndUpdateTotalAmount);
9794

9895
const mutations = basket.mutations;
9996

100-
// Variant 1: simpler but yelding worse API:
101-
export const commitReset1 = commit(mutations.reset);
102-
// Variant 2: a bit more complex but yelding better API:
103-
export const commitReset2 = commitNoPayload(mutations.reset);
97+
export const commitReset = commit(mutations.reset);
10498
export const commitAppendItem = commit(mutations.appendItem);
10599
export const commitSetTotalAmount = commit(mutations.setTotalAmount);
106100
export const commitSelectProducts = commit(mutations.selectProducts);

src/tests/withoutModules/actions.spec.ts

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,31 +29,7 @@ describe("Given store without modules exposing actions", () => {
2929
+ "built with dispatch function", () => {
3030

3131
beforeEach(async () => {
32-
await api.dispatchSelectAvailableItems(store, {});
33-
});
34-
35-
it("mutates state of the module via mutations invoked within the action", () => {
36-
expect(store.state).to.deep.equal({
37-
system: {
38-
userLogin: "abc",
39-
},
40-
basket: {
41-
items: [
42-
{ product: { id: 1, name: "clock", unitPrice: 50 }, isSelected: true },
43-
{ product: { id: 2, name: "newspaper", unitPrice: 20 }, isSelected: true },
44-
{ product: { id: 3, name: "candy", unitPrice: 10 }, isSelected: true },
45-
],
46-
totalAmount: 80,
47-
},
48-
});
49-
});
50-
});
51-
52-
describe("when parameterless action is dispatched using function "
53-
+ "built with dispatchNoPayload function", () => {
54-
55-
beforeEach(async () => {
56-
await api.dispatchSelectAvailableItems2(store);
32+
await api.dispatchSelectAvailableItems(store);
5733
});
5834

5935
it("mutates state of the module via mutations invoked within the action", () => {

src/tests/withoutModules/mutations.spec.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,7 @@ describe("Given store without modules exposing mutations", () => {
2323

2424
describe("when parameterless mutation is made using function built with commit function", () => {
2525
beforeEach(() => {
26-
api.commitReset1(store, {});
27-
});
28-
29-
it("mutates state of the module and not state of other modules", () => {
30-
expect(store.state).to.deep.equal({
31-
system: {
32-
userLogin: "abc",
33-
},
34-
basket: {
35-
items: [],
36-
totalAmount: 0,
37-
},
38-
});
39-
});
40-
});
41-
42-
describe("when parameterless mutation is made using function built "
43-
+ "with commitNoPayload function", () => {
44-
beforeEach(() => {
45-
api.commitReset2(store);
26+
api.commitReset(store);
4627
});
4728

4829
it("mutates state of the module and not state of other modules", () => {

0 commit comments

Comments
 (0)