Skip to content

Commit 9b52804

Browse files
committed
✨ implements strategy pattern instead of direct require Vuex
1 parent 36bcd84 commit 9b52804

File tree

5 files changed

+90
-72
lines changed

5 files changed

+90
-72
lines changed

src/loadable.ts

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,48 @@ import callWithHooks from './callWithHooks';
22
import { LoadableMixinInstance } from './LoadableMixin';
33

44
/**
5-
* Decorate a function to causes loading states changes during its execution. It
6-
* set state as loading when function is init and unset on throws an error or
5+
* An union of any function and functions that have access to `this`
6+
* (Vue instance).
7+
*/
8+
export type Method =
9+
| ((...args: any[]) => any)
10+
| ((this: LoadableMixinInstance, ...args: any[]) => any);
11+
12+
/**
13+
* A Higher-order type to trasnform a method into loadable method that have
14+
* access to `this` (Vue instance) and returns a Promise.
15+
*/
16+
export type LoadableMethod <T extends Method> = (
17+
this: LoadableMixinInstance,
18+
...args: Parameters<T>
19+
) =>
20+
ReturnType<T> extends Promise<any>
21+
? ReturnType<T>
22+
: Promise<ReturnType<T>>;
23+
24+
/**
25+
* Decorate a method to causes loading states changes during its execution. It
26+
* sets state as loading when function is init and unsets on throws an error or
727
* resolve/return.
8-
* @example ```js
28+
* @example
929
* Vue.component('SignInForm', {
1030
* methods: {
1131
* signIn: loadable(async function ({ email, password }) {
1232
* // ...
1333
* }, 'signIn')
1434
* }
15-
* })```
16-
* @param λ - A function, commonly async, which causes loading state changes.
17-
* @param [state] - Loading state name.
35+
* });
36+
* @param method - A method, commonly async, which causes loading state changes.
37+
* @param [state] - Loading state name. It's "unknown" if not defined.
1838
*/
19-
export default function loadable <Return, Params extends any[]> (
20-
λ: (this: LoadableMixinInstance, ...params: Params) => Return | Promise<Return>,
21-
state: string = 'unknown',
22-
): (this: LoadableMixinInstance, ...params: Params) => Promise<Return> {
23-
return function () {
24-
const params = arguments as unknown as Params;
25-
39+
const loadable = <T extends Method> (method: T, state: string = 'unknown') =>
40+
function () {
2641
this.$setLoading(state);
2742

2843
return callWithHooks(
29-
() => λ.apply(this, params),
44+
() => method.apply(this, arguments as any),
3045
() => this.$unsetLoading(state)
3146
);
32-
};
33-
}
47+
} as LoadableMethod<T>;
48+
49+
export default loadable;

src/mapActions.ts

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/mapLoadableActions.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/mapLoadableMethods.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import loadable, { Method, LoadableMethod } from './loadable';
2+
3+
/**
4+
* Type of an object whose keys are `string` and the values are methods.
5+
*/
6+
export type Methods = Record<string, Method>;
7+
8+
/**
9+
* A Higher-order type to transform methods into loadable methods. It keeps keys
10+
* as-is, but values have access to `this` (Vue instance) and returns a Promise.
11+
*/
12+
export type LoadableMethods <T extends Methods> = {
13+
[K in keyof T]: LoadableMethod<T[K]>;
14+
};
15+
16+
/**
17+
* Maps an object, whose keys are `string` and the values are methods, to
18+
* loadable methods that triggers loading states. It uses property's keys as
19+
* loading state names.
20+
* @example
21+
* Vue.component('SignInForm', {
22+
* ...,
23+
* methods: {
24+
* onClick() {
25+
* if (this.$isLoading('signIn') || this.$isLoading('signUp'))
26+
* return;
27+
* // ...
28+
* },
29+
* ...mapLoadableMethods(
30+
* mapActions('authentication', [
31+
* 'signIn',
32+
* 'signUp'
33+
* ])
34+
* )
35+
* }
36+
* });
37+
*/
38+
const mapLoadableMethods = <T extends Methods> (
39+
methods: T
40+
): LoadableMethods<T> => {
41+
const names = Object.keys(methods) as (string & keyof T)[];
42+
43+
return names.reduce(
44+
(loadableMethods, name) => {
45+
loadableMethods[name] = loadable(methods[name], name);
46+
return loadableMethods;
47+
},
48+
Object.create(null) as LoadableMethods<T>
49+
);
50+
};
51+
52+
export default mapLoadableMethods;

src/vue-loadable.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@ declare module 'vue/types/vue' {
3030

3131
export { LoadableMixin };
3232

33-
export { default as loadable } from './loadable';
33+
export { default as loadable, Method, LoadableMethod } from './loadable';
3434

35-
export { default as mapLoadableActions } from './mapLoadableActions';
35+
export {
36+
default as mapLoadableMethods,
37+
Methods,
38+
LoadableMethods
39+
} from './mapLoadableMethods';
3640

3741
/**
3842
* Installs LoadableMixin globally.

0 commit comments

Comments
 (0)