@taicode/common-base 1.6.0 → 1.6.1
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/output/catch/catch.d.ts +33 -9
- package/output/catch/catch.d.ts.map +1 -1
- package/output/catch/catch.js +27 -8
- package/output/catch/catch.test.js +39 -386
- package/package.json +1 -1
package/output/catch/catch.d.ts
CHANGED
|
@@ -1,21 +1,45 @@
|
|
|
1
1
|
type CatchType<F extends () => unknown> = F extends () => PromiseLike<infer R> ? R : F extends () => infer R ? R : never;
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* 成功结果类型
|
|
4
|
+
* 只包含 value 字段,error 字段为 undefined
|
|
4
5
|
*/
|
|
5
|
-
export
|
|
6
|
+
export interface CatchSuccess<T> {
|
|
7
|
+
value: T;
|
|
8
|
+
}
|
|
6
9
|
/**
|
|
7
|
-
*
|
|
10
|
+
* 失败结果类型
|
|
11
|
+
* error 字段类型永远为 unknown(或用户自定义),这样最安全,防止误用。
|
|
12
|
+
* 推荐在 error 分支内用 instanceof/typeof 等类型守卫自行收窄类型。
|
|
8
13
|
*/
|
|
9
|
-
export
|
|
14
|
+
export interface CatchFailure<E> {
|
|
15
|
+
error: E;
|
|
16
|
+
}
|
|
10
17
|
/**
|
|
11
|
-
*
|
|
18
|
+
* 捕获结果联合类型,使用判别联合类型以支持类型守卫
|
|
19
|
+
*
|
|
20
|
+
* 设计说明:
|
|
21
|
+
* - 通过 isError 方法进行类型守卫,推荐始终用 result.isError() 判断是否为错误分支。
|
|
22
|
+
* - isError 方法为 function 写法(而非箭头函数),以支持类型谓词,且 this 不会被转移。
|
|
23
|
+
* - 不建议直接用 error !== undefined 判断错误分支,该方式依赖 error 的值,推荐统一用 isError()。
|
|
12
24
|
*/
|
|
13
|
-
export type CatchResult<T> = CatchSuccess<T> | CatchFailure
|
|
25
|
+
export type CatchResult<T, E = unknown> = (CatchSuccess<T> | CatchFailure<E>) & {
|
|
26
|
+
/**
|
|
27
|
+
* 类型守卫方法,判断当前对象是否为 CatchFailure。
|
|
28
|
+
* function 写法,返回类型谓词,保证类型收窄。
|
|
29
|
+
* 推荐用法:if (result.isError()) { ... }
|
|
30
|
+
*/
|
|
31
|
+
isError: (this: unknown) => this is CatchFailure<E>;
|
|
32
|
+
};
|
|
14
33
|
/**
|
|
15
34
|
* 通用错误捕获函数,支持 PromiseLike 和函数执行
|
|
16
|
-
* 返回
|
|
35
|
+
* 返回 { value, error } 的对象格式,便于类型判断
|
|
36
|
+
*
|
|
37
|
+
* 设计说明:
|
|
38
|
+
* - 支持同步/异步/thenable 场景
|
|
39
|
+
* - 推荐通过 isError() 进行类型守卫
|
|
40
|
+
* - error 字段类型为 unknown,需用户自行收窄
|
|
17
41
|
*/
|
|
18
|
-
export declare function catchIt<T>(input: PromiseLike<T>): Promise<CatchResult<T>>;
|
|
19
|
-
export declare function catchIt<F extends () => unknown>(input: F): Promise<CatchResult<CatchType<F
|
|
42
|
+
export declare function catchIt<T, E = unknown>(input: PromiseLike<T>): Promise<CatchResult<T, E>>;
|
|
43
|
+
export declare function catchIt<F extends () => unknown, E = unknown>(input: F): Promise<CatchResult<CatchType<F>, E>>;
|
|
20
44
|
export {};
|
|
21
45
|
//# sourceMappingURL=catch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catch.d.ts","sourceRoot":"","sources":["../../source/catch/catch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"catch.d.ts","sourceRoot":"","sources":["../../source/catch/catch.ts"],"names":[],"mappings":"AAMA,KAAK,SAAS,CAAC,CAAC,SAAS,MAAM,OAAO,IAAI,CAAC,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAExH;;;GAGG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,KAAK,EAAE,CAAC,CAAA;CACT;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,KAAK,EAAE,CAAC,CAAA;CACT;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG;IAC9E;;;;OAIG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,IAAI,YAAY,CAAC,CAAC,CAAC,CAAA;CACpD,CAAA;AA0BD;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AAChG,wBAAsB,OAAO,CAAC,CAAC,SAAS,MAAM,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA"}
|
package/output/catch/catch.js
CHANGED
|
@@ -2,28 +2,47 @@
|
|
|
2
2
|
function isPromiseLike(value) {
|
|
3
3
|
return value != null && typeof value === 'object' && 'then' in value && typeof value.then === 'function';
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* 构造成功结果对象
|
|
7
|
+
* isError 始终返回 false
|
|
8
|
+
*/
|
|
9
|
+
function createSuccess(value) {
|
|
10
|
+
return {
|
|
11
|
+
value,
|
|
12
|
+
error: undefined,
|
|
13
|
+
isError() { return false; }
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 构造失败结果对象
|
|
18
|
+
* isError 始终返回 true
|
|
19
|
+
*/
|
|
20
|
+
function createFailure(error) {
|
|
21
|
+
return {
|
|
22
|
+
error,
|
|
23
|
+
value: undefined,
|
|
24
|
+
isError() { return true; }
|
|
25
|
+
};
|
|
26
|
+
}
|
|
5
27
|
export async function catchIt(input) {
|
|
6
28
|
try {
|
|
7
29
|
if (isPromiseLike(input)) {
|
|
8
|
-
// 处理 PromiseLike
|
|
9
30
|
const result = await Promise.resolve(input);
|
|
10
|
-
return
|
|
31
|
+
return createSuccess(result);
|
|
11
32
|
}
|
|
12
33
|
else if (typeof input === 'function') {
|
|
13
|
-
// 处理函数
|
|
14
34
|
const result = input();
|
|
15
35
|
if (isPromiseLike(result)) {
|
|
16
|
-
// 如果函数返回 PromiseLike,递归调用
|
|
17
36
|
return catchIt(result);
|
|
18
37
|
}
|
|
19
38
|
else {
|
|
20
|
-
return
|
|
39
|
+
return createSuccess(result);
|
|
21
40
|
}
|
|
22
41
|
}
|
|
23
42
|
}
|
|
24
43
|
catch (error) {
|
|
25
|
-
return
|
|
44
|
+
return createFailure(error);
|
|
26
45
|
}
|
|
27
|
-
//
|
|
28
|
-
return
|
|
46
|
+
// 理论上不会到达这里,兜底类型安全
|
|
47
|
+
return createFailure(new Error('Unexpected input type'));
|
|
29
48
|
}
|
|
@@ -1,390 +1,43 @@
|
|
|
1
|
-
import { describe, it, expect
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { catchIt } from './catch';
|
|
3
3
|
describe('catchIt', () => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
it('应该正确处理不同类型的错误', async () => {
|
|
43
|
-
// Error 对象
|
|
44
|
-
const error = new Error('test error');
|
|
45
|
-
const [, caughtError1] = await catchIt(Promise.reject(error));
|
|
46
|
-
expect(caughtError1).toBe(error);
|
|
47
|
-
// 字符串错误
|
|
48
|
-
const [, caughtError2] = await catchIt(Promise.reject('string error'));
|
|
49
|
-
expect(caughtError2).toBe('string error');
|
|
50
|
-
// 数字错误
|
|
51
|
-
const [, caughtError3] = await catchIt(Promise.reject(404));
|
|
52
|
-
expect(caughtError3).toBe(404);
|
|
53
|
-
// 对象错误
|
|
54
|
-
const objError = { code: 500, message: 'server error' };
|
|
55
|
-
const [, caughtError4] = await catchIt(Promise.reject(objError));
|
|
56
|
-
expect(caughtError4).toBe(objError);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
describe('处理同步函数', () => {
|
|
60
|
-
it('应该正确处理返回值的同步函数', async () => {
|
|
61
|
-
const syncFn = () => 'sync result';
|
|
62
|
-
const [result, error] = await catchIt(syncFn);
|
|
63
|
-
expect(result).toBe('sync result');
|
|
64
|
-
expect(error).toBeUndefined();
|
|
65
|
-
});
|
|
66
|
-
it('应该正确处理抛出错误的同步函数', async () => {
|
|
67
|
-
const errorValue = new Error('sync error');
|
|
68
|
-
const syncFn = () => {
|
|
69
|
-
throw errorValue;
|
|
70
|
-
};
|
|
71
|
-
const [result, error] = await catchIt(syncFn);
|
|
72
|
-
expect(result).toBeUndefined();
|
|
73
|
-
expect(error).toBe(errorValue);
|
|
74
|
-
});
|
|
75
|
-
it('应该正确处理返回不同数据类型的同步函数', async () => {
|
|
76
|
-
// 数字
|
|
77
|
-
const [numberResult] = await catchIt(() => 42);
|
|
78
|
-
expect(numberResult).toBe(42);
|
|
79
|
-
// 字符串
|
|
80
|
-
const [stringResult] = await catchIt(() => 'hello');
|
|
81
|
-
expect(stringResult).toBe('hello');
|
|
82
|
-
// 对象
|
|
83
|
-
const obj = { test: true };
|
|
84
|
-
const [objectResult] = await catchIt(() => obj);
|
|
85
|
-
expect(objectResult).toBe(obj);
|
|
86
|
-
// 数组
|
|
87
|
-
const arr = [1, 2, 3];
|
|
88
|
-
const [arrayResult] = await catchIt(() => arr);
|
|
89
|
-
expect(arrayResult).toBe(arr);
|
|
90
|
-
// boolean
|
|
91
|
-
const [boolResult] = await catchIt(() => true);
|
|
92
|
-
expect(boolResult).toBe(true);
|
|
93
|
-
// null
|
|
94
|
-
const [nullResult] = await catchIt(() => null);
|
|
95
|
-
expect(nullResult).toBeNull();
|
|
96
|
-
// undefined
|
|
97
|
-
const [undefinedResult] = await catchIt(() => undefined);
|
|
98
|
-
expect(undefinedResult).toBeUndefined();
|
|
99
|
-
});
|
|
100
|
-
it('应该确保同步函数被调用', async () => {
|
|
101
|
-
const mockFn = vi.fn(() => 'test');
|
|
102
|
-
await catchIt(mockFn);
|
|
103
|
-
expect(mockFn).toHaveBeenCalledOnce();
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
describe('处理返回 Promise 的函数', () => {
|
|
107
|
-
it('应该正确处理返回成功 Promise 的函数', async () => {
|
|
108
|
-
const asyncFn = () => Promise.resolve('async result');
|
|
109
|
-
const [result, error] = await catchIt(asyncFn);
|
|
110
|
-
expect(result).toBe('async result');
|
|
111
|
-
expect(error).toBeUndefined();
|
|
112
|
-
});
|
|
113
|
-
it('应该正确处理返回失败 Promise 的函数', async () => {
|
|
114
|
-
const errorValue = new Error('async error');
|
|
115
|
-
const asyncFn = () => Promise.reject(errorValue);
|
|
116
|
-
const [result, error] = await catchIt(asyncFn);
|
|
117
|
-
expect(result).toBeUndefined();
|
|
118
|
-
expect(error).toBe(errorValue);
|
|
119
|
-
});
|
|
120
|
-
it('应该正确处理返回不同数据类型 Promise 的函数', async () => {
|
|
121
|
-
// 数字
|
|
122
|
-
const [numberResult] = await catchIt(() => Promise.resolve(123));
|
|
123
|
-
expect(numberResult).toBe(123);
|
|
124
|
-
// 对象
|
|
125
|
-
const obj = { async: true };
|
|
126
|
-
const [objectResult] = await catchIt(() => Promise.resolve(obj));
|
|
127
|
-
expect(objectResult).toBe(obj);
|
|
128
|
-
});
|
|
129
|
-
it('应该确保返回 Promise 的函数被调用', async () => {
|
|
130
|
-
const mockAsyncFn = vi.fn(() => Promise.resolve('test'));
|
|
131
|
-
await catchIt(mockAsyncFn);
|
|
132
|
-
expect(mockAsyncFn).toHaveBeenCalledOnce();
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
describe('边界情况', () => {
|
|
136
|
-
it('应该正确处理函数中抛出的同步错误', async () => {
|
|
137
|
-
const syncError = new Error('sync throw error');
|
|
138
|
-
const errorFn = () => {
|
|
139
|
-
throw syncError;
|
|
140
|
-
};
|
|
141
|
-
const [result, error] = await catchIt(errorFn);
|
|
142
|
-
expect(result).toBeUndefined();
|
|
143
|
-
expect(error).toBe(syncError);
|
|
144
|
-
});
|
|
145
|
-
it('应该正确处理 Promise 链中的错误', async () => {
|
|
146
|
-
const chainError = new Error('chain error');
|
|
147
|
-
const promise = Promise.resolve()
|
|
148
|
-
.then(() => {
|
|
149
|
-
throw chainError;
|
|
150
|
-
});
|
|
151
|
-
const [result, error] = await catchIt(promise);
|
|
152
|
-
expect(result).toBeUndefined();
|
|
153
|
-
expect(error).toBe(chainError);
|
|
154
|
-
});
|
|
155
|
-
it('应该正确处理延迟的 Promise', async () => {
|
|
156
|
-
const delayedPromise = new Promise((resolve) => {
|
|
157
|
-
setTimeout(() => resolve('delayed result'), 10);
|
|
158
|
-
});
|
|
159
|
-
const [result, error] = await catchIt(delayedPromise);
|
|
160
|
-
expect(result).toBe('delayed result');
|
|
161
|
-
expect(error).toBeUndefined();
|
|
162
|
-
});
|
|
163
|
-
it('应该正确处理返回 falsy 值的函数', async () => {
|
|
164
|
-
// 返回 0
|
|
165
|
-
const [zeroResult] = await catchIt(() => 0);
|
|
166
|
-
expect(zeroResult).toBe(0);
|
|
167
|
-
// 返回空字符串
|
|
168
|
-
const [emptyStringResult] = await catchIt(() => '');
|
|
169
|
-
expect(emptyStringResult).toBe('');
|
|
170
|
-
// 返回 false
|
|
171
|
-
const [falseResult] = await catchIt(() => false);
|
|
172
|
-
expect(falseResult).toBe(false);
|
|
173
|
-
// 返回 null
|
|
174
|
-
const [nullResult] = await catchIt(() => null);
|
|
175
|
-
expect(nullResult).toBeNull();
|
|
176
|
-
// 返回 undefined
|
|
177
|
-
const [undefinedResult] = await catchIt(() => undefined);
|
|
178
|
-
expect(undefinedResult).toBeUndefined();
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
describe('类型安全性', () => {
|
|
182
|
-
it('应该保持正确的类型推导 - Promise', async () => {
|
|
183
|
-
// TypeScript 编译时应该能正确推导类型
|
|
184
|
-
const stringPromise = Promise.resolve('string');
|
|
185
|
-
const [stringResult] = await catchIt(stringPromise);
|
|
186
|
-
// stringResult 应该被推导为 string | undefined
|
|
187
|
-
const numberPromise = Promise.resolve(42);
|
|
188
|
-
const [numberResult] = await catchIt(numberPromise);
|
|
189
|
-
// numberResult 应该被推导为 number | undefined
|
|
190
|
-
// 运行时验证
|
|
191
|
-
expect(typeof stringResult).toBe('string');
|
|
192
|
-
expect(typeof numberResult).toBe('number');
|
|
193
|
-
});
|
|
194
|
-
it('应该保持正确的类型推导 - 同步函数', async () => {
|
|
195
|
-
const stringFn = () => 'hello';
|
|
196
|
-
const [stringResult] = await catchIt(stringFn);
|
|
197
|
-
const numberFn = () => 42;
|
|
198
|
-
const [numberResult] = await catchIt(numberFn);
|
|
199
|
-
// 运行时验证
|
|
200
|
-
expect(typeof stringResult).toBe('string');
|
|
201
|
-
expect(typeof numberResult).toBe('number');
|
|
202
|
-
});
|
|
203
|
-
it('应该保持正确的类型推导 - 异步函数', async () => {
|
|
204
|
-
const asyncStringFn = () => Promise.resolve('async hello');
|
|
205
|
-
const [asyncStringResult] = await catchIt(asyncStringFn);
|
|
206
|
-
const asyncNumberFn = () => Promise.resolve(100);
|
|
207
|
-
const [asyncNumberResult] = await catchIt(asyncNumberFn);
|
|
208
|
-
// 运行时验证
|
|
209
|
-
expect(typeof asyncStringResult).toBe('string');
|
|
210
|
-
expect(typeof asyncNumberResult).toBe('number');
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
describe('实际使用场景', () => {
|
|
214
|
-
it('应该适用于 API 调用场景', async () => {
|
|
215
|
-
// 模拟成功的 API 调用
|
|
216
|
-
const mockApiCall = () => Promise.resolve({
|
|
217
|
-
data: { id: 1, name: 'test' },
|
|
218
|
-
status: 200
|
|
219
|
-
});
|
|
220
|
-
const [result, error] = await catchIt(mockApiCall);
|
|
221
|
-
expect(result).toEqual({ data: { id: 1, name: 'test' }, status: 200 });
|
|
222
|
-
expect(error).toBeUndefined();
|
|
223
|
-
// 模拟失败的 API 调用
|
|
224
|
-
const failedApiCall = () => Promise.reject({
|
|
225
|
-
status: 404,
|
|
226
|
-
message: 'Not Found'
|
|
227
|
-
});
|
|
228
|
-
const [failedResult, apiError] = await catchIt(failedApiCall);
|
|
229
|
-
expect(failedResult).toBeUndefined();
|
|
230
|
-
expect(apiError).toEqual({ status: 404, message: 'Not Found' });
|
|
231
|
-
});
|
|
232
|
-
it('应该适用于文件操作场景', async () => {
|
|
233
|
-
// 模拟成功的文件读取
|
|
234
|
-
const mockFileRead = () => Promise.resolve('file content');
|
|
235
|
-
const [content, error] = await catchIt(mockFileRead);
|
|
236
|
-
expect(content).toBe('file content');
|
|
237
|
-
expect(error).toBeUndefined();
|
|
238
|
-
// 模拟失败的文件读取
|
|
239
|
-
const failedFileRead = () => Promise.reject(new Error('File not found'));
|
|
240
|
-
const [failedContent, fileError] = await catchIt(failedFileRead);
|
|
241
|
-
expect(failedContent).toBeUndefined();
|
|
242
|
-
expect(fileError).toBeInstanceOf(Error);
|
|
243
|
-
expect(fileError.message).toBe('File not found');
|
|
244
|
-
});
|
|
245
|
-
it('应该适用于数据解析场景', async () => {
|
|
246
|
-
// 模拟成功的 JSON 解析
|
|
247
|
-
const jsonParseSuccess = () => JSON.parse('{"key": "value"}');
|
|
248
|
-
const [parsed, parseError] = await catchIt(jsonParseSuccess);
|
|
249
|
-
expect(parsed).toEqual({ key: 'value' });
|
|
250
|
-
expect(parseError).toBeUndefined();
|
|
251
|
-
// 模拟失败的 JSON 解析
|
|
252
|
-
const jsonParseFailed = () => JSON.parse('invalid json');
|
|
253
|
-
const [failedParsed, jsonError] = await catchIt(jsonParseFailed);
|
|
254
|
-
expect(failedParsed).toBeUndefined();
|
|
255
|
-
expect(jsonError).toBeInstanceOf(SyntaxError);
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
describe('处理 PromiseLike 对象', () => {
|
|
259
|
-
it('应该正确处理自定义的 PromiseLike 对象', async () => {
|
|
260
|
-
// 创建自定义的 PromiseLike 对象
|
|
261
|
-
const customPromiseLike = {
|
|
262
|
-
then(onfulfilled, onrejected) {
|
|
263
|
-
try {
|
|
264
|
-
const result = onfulfilled?.('custom promise result');
|
|
265
|
-
return Promise.resolve(result);
|
|
266
|
-
}
|
|
267
|
-
catch (error) {
|
|
268
|
-
return onrejected ? Promise.resolve(onrejected(error)) : Promise.reject(error);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
|
-
const [result, error] = await catchIt(customPromiseLike);
|
|
273
|
-
expect(result).toBe('custom promise result');
|
|
274
|
-
expect(error).toBeUndefined();
|
|
275
|
-
});
|
|
276
|
-
it('应该正确处理失败的 PromiseLike 对象', async () => {
|
|
277
|
-
const customError = new Error('custom promise error');
|
|
278
|
-
const failingPromiseLike = {
|
|
279
|
-
then(onfulfilled, onrejected) {
|
|
280
|
-
if (onrejected) {
|
|
281
|
-
return Promise.resolve(onrejected(customError));
|
|
282
|
-
}
|
|
283
|
-
return Promise.reject(customError);
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
const [result, error] = await catchIt(failingPromiseLike);
|
|
287
|
-
expect(result).toBeUndefined();
|
|
288
|
-
expect(error).toBe(customError);
|
|
289
|
-
});
|
|
290
|
-
it('应该正确处理返回 PromiseLike 的函数', async () => {
|
|
291
|
-
const customPromiseLike = {
|
|
292
|
-
then(onfulfilled, onrejected) {
|
|
293
|
-
try {
|
|
294
|
-
const result = onfulfilled?.(42);
|
|
295
|
-
return Promise.resolve(result);
|
|
296
|
-
}
|
|
297
|
-
catch (error) {
|
|
298
|
-
return onrejected ? Promise.resolve(onrejected(error)) : Promise.reject(error);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
const fn = () => customPromiseLike;
|
|
303
|
-
const [result, error] = await catchIt(fn);
|
|
304
|
-
expect(result).toBe(42);
|
|
305
|
-
expect(error).toBeUndefined();
|
|
306
|
-
});
|
|
307
|
-
it('应该正确处理第三方库的 PromiseLike 对象', async () => {
|
|
308
|
-
// 模拟第三方库的 PromiseLike 实现 (如 jQuery.Deferred, Bluebird 等)
|
|
309
|
-
class CustomPromise {
|
|
310
|
-
value;
|
|
311
|
-
isResolved = false;
|
|
312
|
-
isRejected = false;
|
|
313
|
-
rejectionReason;
|
|
314
|
-
constructor(executor) {
|
|
315
|
-
const resolve = (value) => {
|
|
316
|
-
this.value = value;
|
|
317
|
-
this.isResolved = true;
|
|
318
|
-
};
|
|
319
|
-
const reject = (reason) => {
|
|
320
|
-
this.rejectionReason = reason;
|
|
321
|
-
this.isRejected = true;
|
|
322
|
-
};
|
|
323
|
-
try {
|
|
324
|
-
executor(resolve, reject);
|
|
325
|
-
}
|
|
326
|
-
catch (error) {
|
|
327
|
-
reject(error);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
then(onfulfilled, onrejected) {
|
|
331
|
-
if (this.isResolved && onfulfilled) {
|
|
332
|
-
try {
|
|
333
|
-
const result = onfulfilled(this.value);
|
|
334
|
-
return Promise.resolve(result);
|
|
335
|
-
}
|
|
336
|
-
catch (error) {
|
|
337
|
-
return Promise.reject(error);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
else if (this.isRejected && onrejected) {
|
|
341
|
-
try {
|
|
342
|
-
const result = onrejected(this.rejectionReason);
|
|
343
|
-
return Promise.resolve(result);
|
|
344
|
-
}
|
|
345
|
-
catch (error) {
|
|
346
|
-
return Promise.reject(error);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
else if (this.isRejected) {
|
|
350
|
-
return Promise.reject(this.rejectionReason);
|
|
351
|
-
}
|
|
352
|
-
return Promise.resolve(this.value);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
const customPromise = new CustomPromise((resolve) => {
|
|
356
|
-
resolve('third party promise');
|
|
357
|
-
});
|
|
358
|
-
const [result, error] = await catchIt(customPromise);
|
|
359
|
-
expect(result).toBe('third party promise');
|
|
360
|
-
expect(error).toBeUndefined();
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
describe('类型判断优化', () => {
|
|
364
|
-
it('应该支持联合类型的类型判断', async () => {
|
|
365
|
-
// 成功情况的类型判断
|
|
366
|
-
const successResult = await catchIt(Promise.resolve('success'));
|
|
367
|
-
if (successResult[1] === undefined) {
|
|
368
|
-
// 在这个分支中,TypeScript 应该能够推断出 successResult[0] 是 string 类型
|
|
369
|
-
expect(typeof successResult[0]).toBe('string');
|
|
370
|
-
expect(successResult[0]).toBe('success');
|
|
371
|
-
}
|
|
372
|
-
// 失败情况的类型判断
|
|
373
|
-
const failureResult = await catchIt(Promise.reject(new Error('failed')));
|
|
374
|
-
if (failureResult[0] === undefined) {
|
|
375
|
-
// 在这个分支中,TypeScript 应该能够推断出 failureResult[1] 是 unknown 类型
|
|
376
|
-
expect(failureResult[1]).toBeInstanceOf(Error);
|
|
377
|
-
expect(failureResult[1].message).toBe('failed');
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
it('应该支持函数的类型判断', async () => {
|
|
381
|
-
const fn = () => 42;
|
|
382
|
-
const result = await catchIt(fn);
|
|
383
|
-
if (result[1] === undefined) {
|
|
384
|
-
// 成功情况下,result[0] 应该是 number 类型
|
|
385
|
-
expect(typeof result[0]).toBe('number');
|
|
386
|
-
expect(result[0]).toBe(42);
|
|
387
|
-
}
|
|
388
|
-
});
|
|
4
|
+
it('同步函数返回值应为 value,error 为 undefined,isError 为 false', async () => {
|
|
5
|
+
const result = await catchIt(() => 123);
|
|
6
|
+
expect(result.value).toBe(123);
|
|
7
|
+
expect(result.error).toBeUndefined();
|
|
8
|
+
expect(result.isError()).toBe(false);
|
|
9
|
+
});
|
|
10
|
+
it('异步函数返回值应为 value,error 为 undefined,isError 为 false', async () => {
|
|
11
|
+
const result = await catchIt(async () => 456);
|
|
12
|
+
expect(result.value).toBe(456);
|
|
13
|
+
expect(result.error).toBeUndefined();
|
|
14
|
+
expect(result.isError()).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
it('同步抛出异常时应返回 error,value 为 undefined,isError 为 true', async () => {
|
|
17
|
+
const error = new Error('fail');
|
|
18
|
+
const result = await catchIt(() => { throw error; });
|
|
19
|
+
expect(result.value).toBeUndefined();
|
|
20
|
+
expect(result.error).toBe(error);
|
|
21
|
+
expect(result.isError()).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
it('异步抛出异常时应返回 error,value 为 undefined,isError 为 true', async () => {
|
|
24
|
+
const error = new Error('fail-async');
|
|
25
|
+
const result = await catchIt(() => Promise.reject(error));
|
|
26
|
+
expect(result.value).toBeUndefined();
|
|
27
|
+
expect(result.error).toBe(error);
|
|
28
|
+
expect(result.isError()).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
it('PromiseLike resolve 时应返回 value,error 为 undefined,isError 为 false', async () => {
|
|
31
|
+
const result = await catchIt(Promise.resolve('ok'));
|
|
32
|
+
expect(result.value).toBe('ok');
|
|
33
|
+
expect(result.error).toBeUndefined();
|
|
34
|
+
expect(result.isError()).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
it('PromiseLike reject 时应返回 error,value 为 undefined,isError 为 true', async () => {
|
|
37
|
+
const error = new Error('promise-fail');
|
|
38
|
+
const result = await catchIt(Promise.reject(error));
|
|
39
|
+
expect(result.value).toBeUndefined();
|
|
40
|
+
expect(result.error).toBe(error);
|
|
41
|
+
expect(result.isError()).toBe(true);
|
|
389
42
|
});
|
|
390
43
|
});
|