@nickyzj2023/utils 1.0.10 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dom.d.ts +8 -8
- package/dist/hoc.d.ts +43 -41
- package/dist/index.d.ts +5 -4
- package/dist/index.js +2 -6
- package/dist/is.d.ts +6 -6
- package/dist/network.d.ts +48 -40
- package/dist/object.d.ts +1 -0
- package/dist/time.d.ts +7 -0
- package/docs/assets/highlight.css +92 -92
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/functions/fetcher.html +14 -16
- package/docs/functions/isObject.html +3 -7
- package/docs/functions/sleep.html +6 -0
- package/docs/functions/timeLog.html +5 -5
- package/docs/functions/to.html +7 -11
- package/docs/functions/withCache.html +12 -12
- package/docs/modules.html +1 -1
- package/package.json +1 -1
- package/src/hoc.ts +114 -109
- package/src/index.ts +5 -4
- package/src/network.ts +106 -101
- package/src/object.ts +32 -0
- package/src/time.ts +11 -0
package/src/network.ts
CHANGED
|
@@ -1,101 +1,106 @@
|
|
|
1
|
-
import { isObject } from "./is";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* @
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* // 用法1:创建客户端
|
|
18
|
-
* const api = fetcher("https://nickyzj.run:3030", { headers: { Authorization: "Bearer token" } });
|
|
19
|
-
* const res = await api.get<Blog>("/blogs/hello-world");
|
|
20
|
-
*
|
|
21
|
-
* // 用法2:直接发送请求
|
|
22
|
-
* const res = await fetcher().get<Blog>("https://nickyzj.run:3030/blogs/hello-world");
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
url:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
*
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
1
|
+
import { isObject } from "./is";
|
|
2
|
+
import { mergeObjects } from "./object";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 基于 Fetch API 的请求客户端
|
|
6
|
+
* @param baseURL 接口前缀,如 https://nickyzj.run:3030,也可以不填
|
|
7
|
+
* @param defaultOptions 客户端级别的请求选项,方法级别的选项会覆盖这里的相同值
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* 特性:
|
|
11
|
+
* - 合并客户端级别、方法级别的请求选项
|
|
12
|
+
* - 在 body 里直接传递对象
|
|
13
|
+
* - 可选择使用 to() 处理返回结果为 [Error, Response]
|
|
14
|
+
* - 可选择使用 withCache() 缓存请求结果
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // 用法1:创建客户端
|
|
18
|
+
* const api = fetcher("https://nickyzj.run:3030", { headers: { Authorization: "Bearer token" } });
|
|
19
|
+
* const res = await api.get<Blog>("/blogs/hello-world");
|
|
20
|
+
*
|
|
21
|
+
* // 用法2:直接发送请求
|
|
22
|
+
* const res = await fetcher().get<Blog>("https://nickyzj.run:3030/blogs/hello-world");
|
|
23
|
+
*
|
|
24
|
+
* // 安全处理返回结果
|
|
25
|
+
* const [error, data] = await to(api.get<Blog>("/blogs/hello-world"));
|
|
26
|
+
* if (error) {
|
|
27
|
+
* console.error(error);
|
|
28
|
+
* return;
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* // 缓存请求结果
|
|
32
|
+
* const getBlogs = withCache(api.get);
|
|
33
|
+
* await getBlogs("/blogs");
|
|
34
|
+
* await sleep(1000);
|
|
35
|
+
* await getBlogs("/blogs"); // 不请求,使用缓存结果
|
|
36
|
+
*/
|
|
37
|
+
export const fetcher = (baseURL = "", defaultOptions: RequestInit = {}) => {
|
|
38
|
+
const createRequest = async <T>(
|
|
39
|
+
path: string,
|
|
40
|
+
requestOptions: RequestInit = {},
|
|
41
|
+
) => {
|
|
42
|
+
// 构建完整 URL
|
|
43
|
+
const url = baseURL ? `${baseURL}${path}` : path;
|
|
44
|
+
|
|
45
|
+
// 合并 options
|
|
46
|
+
const options = mergeObjects(defaultOptions, requestOptions);
|
|
47
|
+
|
|
48
|
+
// 转换 body 为字符串
|
|
49
|
+
if (isObject(options.body)) {
|
|
50
|
+
options.body = JSON.stringify(options.body);
|
|
51
|
+
options.headers = {
|
|
52
|
+
"Content-Type": "application/json",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 发送请求
|
|
57
|
+
const response = await fetch(url, options);
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
throw new Error(response.statusText);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const data = await response.json();
|
|
63
|
+
return data as T;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
get: <T>(url: string, options: Omit<RequestInit, "method"> = {}) =>
|
|
68
|
+
createRequest<T>(url, { ...options, method: "GET" }),
|
|
69
|
+
|
|
70
|
+
post: <T>(
|
|
71
|
+
url: string,
|
|
72
|
+
body: any,
|
|
73
|
+
options: Omit<RequestInit, "method" | "body"> = {},
|
|
74
|
+
) => createRequest<T>(url, { ...options, method: "POST", body }),
|
|
75
|
+
|
|
76
|
+
put: <T>(
|
|
77
|
+
url: string,
|
|
78
|
+
body: any,
|
|
79
|
+
options: Omit<RequestInit, "method" | "body"> = {},
|
|
80
|
+
) => createRequest<T>(url, { ...options, method: "PUT", body }),
|
|
81
|
+
|
|
82
|
+
delete: <T>(
|
|
83
|
+
url: string,
|
|
84
|
+
options: Omit<RequestInit, "method" | "body"> = {},
|
|
85
|
+
) => createRequest<T>(url, { ...options, method: "DELETE" }),
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Go 语言风格的异步处理方式
|
|
91
|
+
* @param promise 一个能被 await 的异步函数
|
|
92
|
+
* @returns 如果成功,返回 [null, 异步函数结果],否则返回 [Error, undefined]
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* const [error, response] = await to(fetcher().get<Blog>("/blogs/hello-world"));
|
|
96
|
+
*/
|
|
97
|
+
export const to = async <T, U = Error>(
|
|
98
|
+
promise: Promise<T>,
|
|
99
|
+
): Promise<[null, T] | [U, undefined]> => {
|
|
100
|
+
try {
|
|
101
|
+
const response = await promise;
|
|
102
|
+
return [null, response];
|
|
103
|
+
} catch (error) {
|
|
104
|
+
return [error as U, undefined];
|
|
105
|
+
}
|
|
106
|
+
};
|
package/src/object.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { isObject } from "./is";
|
|
2
|
+
|
|
3
|
+
export const mergeObjects = (...objects: Record<string, any>[]) => {
|
|
4
|
+
return objects.reduce(
|
|
5
|
+
(acc: Record<string, any>, obj: Record<string, any>) => {
|
|
6
|
+
if (!isObject(obj)) {
|
|
7
|
+
return acc;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
Object.keys(obj).forEach((key) => {
|
|
11
|
+
const accValue = acc[key];
|
|
12
|
+
const objValue = obj[key];
|
|
13
|
+
|
|
14
|
+
// 如果两个值都是数组,则合并数组
|
|
15
|
+
if (Array.isArray(accValue) && Array.isArray(objValue)) {
|
|
16
|
+
acc[key] = [...accValue, ...objValue];
|
|
17
|
+
}
|
|
18
|
+
// 如果两个值都是对象,则递归合并
|
|
19
|
+
else if (isObject(objValue) && isObject(accValue)) {
|
|
20
|
+
acc[key] = mergeObjects(accValue, objValue);
|
|
21
|
+
}
|
|
22
|
+
// 其他情况直接覆盖
|
|
23
|
+
else {
|
|
24
|
+
acc[key] = objValue;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return acc;
|
|
29
|
+
},
|
|
30
|
+
{},
|
|
31
|
+
);
|
|
32
|
+
};
|
package/src/time.ts
ADDED