go-go-try 6.1.0 → 6.2.0
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/index.d.cts +4 -0
- package/dist/index.d.mts +4 -0
- package/package.json +53 -53
- package/src/index.test.ts +367 -337
- package/src/index.ts +74 -68
package/dist/index.d.cts
CHANGED
|
@@ -26,6 +26,8 @@ declare function failure<E>(error: E): Failure<E>;
|
|
|
26
26
|
* // With a promise
|
|
27
27
|
* const [err, result] = await goTry(fetch('https://api.example.com/data'));
|
|
28
28
|
*/
|
|
29
|
+
declare function goTry<T>(fn: () => never): Result<string, never>;
|
|
30
|
+
declare function goTry<T>(fn: () => Promise<T>): Promise<Result<string, T>>;
|
|
29
31
|
declare function goTry<T>(promise: Promise<T>): Promise<Result<string, T>>;
|
|
30
32
|
declare function goTry<T>(fn: () => T): Result<string, T>;
|
|
31
33
|
declare function goTry<T>(value: T): Result<string, T>;
|
|
@@ -50,6 +52,8 @@ declare function goTry<T>(value: T): Result<string, T>;
|
|
|
50
52
|
* // With a promise
|
|
51
53
|
* const [err, result] = await goTryRaw(fetch('https://api.example.com/data'));
|
|
52
54
|
*/
|
|
55
|
+
declare function goTryRaw<T, E = Error>(fn: () => never): Result<E, never>;
|
|
56
|
+
declare function goTryRaw<T, E = Error>(fn: () => Promise<T>): Promise<Result<E, T>>;
|
|
53
57
|
declare function goTryRaw<T, E = Error>(promise: Promise<T>): Promise<Result<E, T>>;
|
|
54
58
|
declare function goTryRaw<T, E = Error>(fn: () => T): Result<E, T>;
|
|
55
59
|
declare function goTryRaw<T, E = Error>(value: T): Result<E, T>;
|
package/dist/index.d.mts
CHANGED
|
@@ -26,6 +26,8 @@ declare function failure<E>(error: E): Failure<E>;
|
|
|
26
26
|
* // With a promise
|
|
27
27
|
* const [err, result] = await goTry(fetch('https://api.example.com/data'));
|
|
28
28
|
*/
|
|
29
|
+
declare function goTry<T>(fn: () => never): Result<string, never>;
|
|
30
|
+
declare function goTry<T>(fn: () => Promise<T>): Promise<Result<string, T>>;
|
|
29
31
|
declare function goTry<T>(promise: Promise<T>): Promise<Result<string, T>>;
|
|
30
32
|
declare function goTry<T>(fn: () => T): Result<string, T>;
|
|
31
33
|
declare function goTry<T>(value: T): Result<string, T>;
|
|
@@ -50,6 +52,8 @@ declare function goTry<T>(value: T): Result<string, T>;
|
|
|
50
52
|
* // With a promise
|
|
51
53
|
* const [err, result] = await goTryRaw(fetch('https://api.example.com/data'));
|
|
52
54
|
*/
|
|
55
|
+
declare function goTryRaw<T, E = Error>(fn: () => never): Result<E, never>;
|
|
56
|
+
declare function goTryRaw<T, E = Error>(fn: () => Promise<T>): Promise<Result<E, T>>;
|
|
53
57
|
declare function goTryRaw<T, E = Error>(promise: Promise<T>): Promise<Result<E, T>>;
|
|
54
58
|
declare function goTryRaw<T, E = Error>(fn: () => T): Result<E, T>;
|
|
55
59
|
declare function goTryRaw<T, E = Error>(value: T): Result<E, T>;
|
package/package.json
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
2
|
+
"name": "go-go-try",
|
|
3
|
+
"version": "6.2.0",
|
|
4
|
+
"description": "Tries to execute a sync/async function, returns a result tuple",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": "thelinuxlich/go-go-try",
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "Alisson Cavalcante Agiani",
|
|
9
|
+
"email": "thelinuxlich@gmail.com"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "./dist/index.cjs",
|
|
13
|
+
"module": "./dist/index.mjs",
|
|
14
|
+
"types": "./dist/index.d.mts",
|
|
15
|
+
"exports": {
|
|
16
|
+
"require": {
|
|
17
|
+
"types": "./dist/index.d.cts",
|
|
18
|
+
"default": "./dist/index.cjs"
|
|
19
|
+
},
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./dist/index.d.mts",
|
|
22
|
+
"default": "./dist/index.mjs"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=16"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "pkgroll",
|
|
30
|
+
"lint": "biome lint --write src/*.ts",
|
|
31
|
+
"test": "npm run build && npm run lint && vitest run"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"errors",
|
|
35
|
+
"try",
|
|
36
|
+
"catch",
|
|
37
|
+
"error handling",
|
|
38
|
+
"nice-try",
|
|
39
|
+
"good-try",
|
|
40
|
+
"neverthrow",
|
|
41
|
+
"ts-result",
|
|
42
|
+
"effect",
|
|
43
|
+
"go-go-try",
|
|
44
|
+
"gotry",
|
|
45
|
+
"go-try"
|
|
46
|
+
],
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@ark/attest": "^0.46.0",
|
|
49
|
+
"@biomejs/biome": "^1.9.4",
|
|
50
|
+
"pkgroll": "^2.12.1",
|
|
51
|
+
"tsx": "^4.19.3",
|
|
52
|
+
"typescript": "^5.8.3",
|
|
53
|
+
"vitest": "^3.1.2"
|
|
54
|
+
}
|
|
55
55
|
}
|
package/src/index.test.ts
CHANGED
|
@@ -3,368 +3,398 @@ import { assert, describe, test } from 'vitest'
|
|
|
3
3
|
import { type Result, goTry, goTryRaw, isFailure, isSuccess } from './index.js'
|
|
4
4
|
|
|
5
5
|
test(`value returned by callback is used when callback doesn't throw`, async () => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
6
|
+
const fn = () => 'value'
|
|
7
|
+
|
|
8
|
+
// Test with function
|
|
9
|
+
const result1 = goTry(fn)
|
|
10
|
+
const result2 = goTryRaw(fn)
|
|
11
|
+
|
|
12
|
+
// Test destructuring
|
|
13
|
+
const [err1, value] = result1
|
|
14
|
+
const [err2, value2] = result2
|
|
15
|
+
|
|
16
|
+
// Test type guards
|
|
17
|
+
assert.equal(isSuccess(result1), true)
|
|
18
|
+
assert.equal(isSuccess(result2), true)
|
|
19
|
+
assert.equal(isFailure(result1), false)
|
|
20
|
+
assert.equal(isFailure(result2), false)
|
|
21
|
+
|
|
22
|
+
// Test values
|
|
23
|
+
assert.equal(value, 'value')
|
|
24
|
+
assert.equal(value2, 'value')
|
|
25
|
+
assert.equal(err1, undefined)
|
|
26
|
+
assert.equal(err2, undefined)
|
|
27
27
|
})
|
|
28
28
|
|
|
29
29
|
test('if function throws undefined, err should be "undefined"', async () => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
30
|
+
const fn = () => {
|
|
31
|
+
throw undefined
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Test with function that throws undefined
|
|
35
|
+
const result1 = goTry(fn)
|
|
36
|
+
const result2 = goTryRaw(fn)
|
|
37
|
+
|
|
38
|
+
// Test destructuring
|
|
39
|
+
const [err1, value] = result1
|
|
40
|
+
const [err2, value2] = result2
|
|
41
|
+
|
|
42
|
+
// Test type guards
|
|
43
|
+
assert.equal(isSuccess(result1), false)
|
|
44
|
+
assert.equal(isSuccess(result2), false)
|
|
45
|
+
assert.equal(isFailure(result1), true)
|
|
46
|
+
assert.equal(isFailure(result2), true)
|
|
47
|
+
|
|
48
|
+
// Test values
|
|
49
|
+
assert.equal(value, undefined)
|
|
50
|
+
assert.equal(value2, undefined)
|
|
51
|
+
assert.equal(err1, 'undefined')
|
|
52
|
+
assert.equal(typeof err2, 'object')
|
|
53
53
|
})
|
|
54
54
|
|
|
55
55
|
test('if callback throws, value should be undefined and err should contain the error message', async () => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
56
|
+
const fn = () => {
|
|
57
|
+
return JSON.parse('{/') as string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Test with function that throws
|
|
61
|
+
const result1 = goTry(fn)
|
|
62
|
+
const result2 = goTryRaw(fn)
|
|
63
|
+
|
|
64
|
+
// Test destructuring
|
|
65
|
+
const [err1, value] = result1
|
|
66
|
+
const [err2, value2] = result2
|
|
67
|
+
|
|
68
|
+
// Test type guards
|
|
69
|
+
assert.equal(isSuccess(result1), false)
|
|
70
|
+
assert.equal(isSuccess(result2), false)
|
|
71
|
+
assert.equal(isFailure(result1), true)
|
|
72
|
+
assert.equal(isFailure(result2), true)
|
|
73
|
+
|
|
74
|
+
// Test values
|
|
75
|
+
assert.equal(value, undefined)
|
|
76
|
+
assert.equal(value2, undefined)
|
|
77
|
+
assert.equal(typeof err1, 'string')
|
|
78
|
+
assert.equal(typeof err2, 'object')
|
|
79
|
+
assert.equal(typeof err2?.message, 'string')
|
|
80
80
|
})
|
|
81
81
|
|
|
82
82
|
test('first parameter accepts promises and makes the function async', async () => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
83
|
+
const promise = Promise.resolve('value')
|
|
84
|
+
|
|
85
|
+
// Test with promise
|
|
86
|
+
const result1 = await goTry(promise)
|
|
87
|
+
const result2 = await goTryRaw(promise)
|
|
88
|
+
|
|
89
|
+
// Test destructuring
|
|
90
|
+
const [err1, value] = result1
|
|
91
|
+
const [err2, value2] = result2
|
|
92
|
+
|
|
93
|
+
// Test type guards
|
|
94
|
+
assert.equal(isSuccess(result1), true)
|
|
95
|
+
assert.equal(isSuccess(result2), true)
|
|
96
|
+
assert.equal(isFailure(result1), false)
|
|
97
|
+
assert.equal(isFailure(result2), false)
|
|
98
|
+
|
|
99
|
+
// Test values
|
|
100
|
+
assert.equal(value, 'value')
|
|
101
|
+
assert.equal(value2, 'value')
|
|
102
|
+
assert.equal(err1, undefined)
|
|
103
|
+
assert.equal(err2, undefined)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test("if it's a function returning a Promise, should unwrap the value correctly to T", async () => {
|
|
107
|
+
const fn = () => Promise.resolve('value')
|
|
108
|
+
|
|
109
|
+
// Test with function that returns a promise
|
|
110
|
+
const result1 = await goTry(fn)
|
|
111
|
+
const result2 = await goTryRaw(fn)
|
|
112
|
+
|
|
113
|
+
// Test destructuring
|
|
114
|
+
const [err1, value] = result1
|
|
115
|
+
const [err2, value2] = result2
|
|
116
|
+
|
|
117
|
+
attest<string | undefined>(err1)
|
|
118
|
+
attest<string | undefined>(value)
|
|
119
|
+
|
|
120
|
+
attest<Error | undefined>(err2)
|
|
121
|
+
attest<string | undefined>(value2)
|
|
122
|
+
|
|
123
|
+
// Test type guards
|
|
124
|
+
assert.equal(isSuccess(result1), true)
|
|
125
|
+
assert.equal(isSuccess(result2), true)
|
|
126
|
+
assert.equal(isFailure(result1), false)
|
|
127
|
+
assert.equal(isFailure(result2), false)
|
|
128
|
+
|
|
129
|
+
// Test values
|
|
130
|
+
assert.equal(value, 'value')
|
|
131
|
+
assert.equal(value2, 'value')
|
|
132
|
+
assert.equal(err1, undefined)
|
|
133
|
+
assert.equal(err2, undefined)
|
|
104
134
|
})
|
|
105
135
|
|
|
106
136
|
test('if async callback throws, value should be undefined and err should contain the error message', async () => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
137
|
+
const promise = Promise.reject(new Error('error'))
|
|
138
|
+
|
|
139
|
+
// Test with promise that rejects
|
|
140
|
+
const result1 = await goTry(promise)
|
|
141
|
+
const result2 = await goTryRaw<Error>(promise)
|
|
142
|
+
|
|
143
|
+
// Test destructuring
|
|
144
|
+
const [err, value] = result1
|
|
145
|
+
const [err2, value2] = result2
|
|
146
|
+
|
|
147
|
+
// Test type guards
|
|
148
|
+
assert.equal(isSuccess(result1), false)
|
|
149
|
+
assert.equal(isSuccess(result2), false)
|
|
150
|
+
assert.equal(isFailure(result1), true)
|
|
151
|
+
assert.equal(isFailure(result2), true)
|
|
152
|
+
|
|
153
|
+
// Test values
|
|
154
|
+
assert.equal(value, undefined)
|
|
155
|
+
assert.equal(value2, undefined)
|
|
156
|
+
assert.equal(err, 'error')
|
|
157
|
+
assert.equal(typeof err2, 'object')
|
|
158
|
+
assert.equal(err2?.message, 'error')
|
|
129
159
|
})
|
|
130
160
|
|
|
131
161
|
test('direct values work too', () => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
162
|
+
// Test with direct value
|
|
163
|
+
const result1 = goTry('value')
|
|
164
|
+
const result2 = goTryRaw('value')
|
|
165
|
+
|
|
166
|
+
// Test destructuring
|
|
167
|
+
const [err1, value] = result1
|
|
168
|
+
const [err2, value2] = result2
|
|
169
|
+
|
|
170
|
+
// Test values
|
|
171
|
+
assert.equal(value, 'value')
|
|
172
|
+
assert.equal(value2, 'value')
|
|
173
|
+
assert.equal(err1, undefined)
|
|
174
|
+
assert.equal(err2, undefined)
|
|
145
175
|
})
|
|
146
176
|
|
|
147
177
|
test('async functions work correctly', async () => {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
178
|
+
// Define an async function
|
|
179
|
+
function asyncFn() {
|
|
180
|
+
return Promise.resolve(42)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Test with async function
|
|
184
|
+
const result1 = await goTry(asyncFn())
|
|
185
|
+
const result2 = await goTryRaw(asyncFn())
|
|
186
|
+
|
|
187
|
+
// Test destructuring
|
|
188
|
+
const [err1, value] = result1
|
|
189
|
+
const [err2, value2] = result2
|
|
190
|
+
|
|
191
|
+
// Test values
|
|
192
|
+
assert.equal(value, 42)
|
|
193
|
+
assert.equal(value2, 42)
|
|
194
|
+
assert.equal(err1, undefined)
|
|
195
|
+
assert.equal(err2, undefined)
|
|
166
196
|
})
|
|
167
197
|
|
|
168
198
|
test('async functions that throw work correctly', async () => {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
199
|
+
// Define an async function that throws
|
|
200
|
+
async function asyncFnThatThrows() {
|
|
201
|
+
await 1
|
|
202
|
+
throw new Error('async error')
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Test with async function that throws
|
|
206
|
+
const result1 = await goTry(asyncFnThatThrows())
|
|
207
|
+
const result2 = await goTryRaw(asyncFnThatThrows())
|
|
208
|
+
|
|
209
|
+
// Test destructuring
|
|
210
|
+
const [err1, value] = result1
|
|
211
|
+
const [err2, value2] = result2
|
|
212
|
+
|
|
213
|
+
// Test values
|
|
214
|
+
assert.equal(value, undefined)
|
|
215
|
+
assert.equal(value2, undefined)
|
|
216
|
+
assert.equal(err1, 'async error')
|
|
217
|
+
assert.equal(typeof err2, 'object')
|
|
218
|
+
assert.equal(err2?.message, 'async error')
|
|
189
219
|
})
|
|
190
220
|
|
|
191
221
|
describe('goTry type tests', () => {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
222
|
+
test('synchronous function returns correct types', () => {
|
|
223
|
+
const fn = () => 'value'
|
|
224
|
+
const result = goTry(fn)
|
|
225
|
+
|
|
226
|
+
// Check the result type
|
|
227
|
+
attest<Result<string, string>>(result)
|
|
228
|
+
|
|
229
|
+
// Check the destructured types
|
|
230
|
+
const [err, value] = result
|
|
231
|
+
attest<string | undefined>(err)
|
|
232
|
+
attest<string | undefined>(value)
|
|
233
|
+
|
|
234
|
+
// When destructured, the types should be narrowed correctly
|
|
235
|
+
if (err === undefined) {
|
|
236
|
+
attest<string>(value)
|
|
237
|
+
} else {
|
|
238
|
+
attest<undefined>(value)
|
|
239
|
+
}
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
test('direct value returns correct types', () => {
|
|
243
|
+
const result = goTry('value')
|
|
244
|
+
|
|
245
|
+
// Check the result type
|
|
246
|
+
attest<Result<string, string>>(result)
|
|
247
|
+
|
|
248
|
+
// Check the destructured types
|
|
249
|
+
const [err, value] = result
|
|
250
|
+
attest<string | undefined>(err)
|
|
251
|
+
attest<string | undefined>(value)
|
|
252
|
+
|
|
253
|
+
// When destructured, the types should be narrowed correctly
|
|
254
|
+
if (err === undefined) {
|
|
255
|
+
attest<string>(value)
|
|
256
|
+
} else {
|
|
257
|
+
attest<undefined>(value)
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
test('promise returns correct types', async () => {
|
|
262
|
+
const promise = Promise.resolve('value')
|
|
263
|
+
const result = await goTry(promise)
|
|
264
|
+
|
|
265
|
+
// Check the result type
|
|
266
|
+
attest<Result<string, string>>(result)
|
|
267
|
+
|
|
268
|
+
// Check the destructured types
|
|
269
|
+
const [err, value] = result
|
|
270
|
+
attest<string | undefined>(err)
|
|
271
|
+
attest<string | undefined>(value)
|
|
272
|
+
|
|
273
|
+
// When destructured, the types should be narrowed correctly
|
|
274
|
+
if (err === undefined) {
|
|
275
|
+
attest<string>(value)
|
|
276
|
+
} else {
|
|
277
|
+
attest<undefined>(value)
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
test('async function returns correct types', async () => {
|
|
282
|
+
const asyncFn = async () => 'value'
|
|
283
|
+
const result = await goTry(asyncFn())
|
|
284
|
+
|
|
285
|
+
// Check the result type
|
|
286
|
+
attest<Result<string, string>>(result)
|
|
287
|
+
|
|
288
|
+
// Check the destructured types
|
|
289
|
+
const [err, value] = result
|
|
290
|
+
attest<string | undefined>(err)
|
|
291
|
+
attest<string | undefined>(value)
|
|
292
|
+
|
|
293
|
+
// When destructured, the types should be narrowed correctly
|
|
294
|
+
if (err === undefined) {
|
|
295
|
+
attest<string>(value)
|
|
296
|
+
} else {
|
|
297
|
+
attest<undefined>(value)
|
|
298
|
+
}
|
|
299
|
+
})
|
|
270
300
|
})
|
|
271
301
|
|
|
272
302
|
describe('goTryRaw type tests', () => {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
303
|
+
test('type inference works correctly', () => {
|
|
304
|
+
const fn = () => 'value'
|
|
305
|
+
const result = goTryRaw(fn)
|
|
306
|
+
|
|
307
|
+
// Check the result type
|
|
308
|
+
attest<Result<Error, string>>(result)
|
|
309
|
+
|
|
310
|
+
// Check the destructured types
|
|
311
|
+
const [err, value] = result
|
|
312
|
+
attest<Error | undefined>(err)
|
|
313
|
+
attest<string | undefined>(value)
|
|
314
|
+
|
|
315
|
+
// When destructured, the types should be narrowed correctly
|
|
316
|
+
if (err === undefined) {
|
|
317
|
+
attest<string>(value)
|
|
318
|
+
} else {
|
|
319
|
+
attest<undefined>(value)
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
test('synchronous function returns correct types', () => {
|
|
323
|
+
const fn = () => 'value'
|
|
324
|
+
const result = goTryRaw(fn)
|
|
325
|
+
|
|
326
|
+
// Check the result type
|
|
327
|
+
attest<Result<Error, string>>(result)
|
|
328
|
+
|
|
329
|
+
// Check the destructured types
|
|
330
|
+
const [err, value] = result
|
|
331
|
+
attest<Error | undefined>(err)
|
|
332
|
+
attest<string | undefined>(value)
|
|
333
|
+
|
|
334
|
+
// When destructured, the types should be narrowed correctly
|
|
335
|
+
if (err === undefined) {
|
|
336
|
+
attest<string>(value)
|
|
337
|
+
} else {
|
|
338
|
+
attest<undefined>(value)
|
|
339
|
+
}
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
test('direct value returns correct types', () => {
|
|
343
|
+
const result = goTryRaw('value')
|
|
344
|
+
|
|
345
|
+
// Check the result type
|
|
346
|
+
attest<Result<Error, string>>(result)
|
|
347
|
+
|
|
348
|
+
// Check the destructured types
|
|
349
|
+
const [err, value] = result
|
|
350
|
+
attest<Error | undefined>(err)
|
|
351
|
+
attest<string | undefined>(value)
|
|
352
|
+
|
|
353
|
+
// When destructured, the types should be narrowed correctly
|
|
354
|
+
if (err === undefined) {
|
|
355
|
+
attest<string>(value)
|
|
356
|
+
} else {
|
|
357
|
+
attest<undefined>(value)
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
test('promise returns correct types', async () => {
|
|
362
|
+
const promise = Promise.resolve('value')
|
|
363
|
+
const result = await goTryRaw(promise)
|
|
364
|
+
|
|
365
|
+
// Check the result type
|
|
366
|
+
attest<Result<Error, string>>(result)
|
|
367
|
+
|
|
368
|
+
// Check the destructured types
|
|
369
|
+
const [err, value] = result
|
|
370
|
+
attest<Error | undefined>(err)
|
|
371
|
+
attest<string | undefined>(value)
|
|
372
|
+
|
|
373
|
+
// When destructured, the types should be narrowed correctly
|
|
374
|
+
if (err === undefined) {
|
|
375
|
+
attest<string>(value)
|
|
376
|
+
} else {
|
|
377
|
+
attest<undefined>(value)
|
|
378
|
+
}
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
test('async function returns correct types', async () => {
|
|
382
|
+
const asyncFn = async () => 'value'
|
|
383
|
+
const result = await goTryRaw(asyncFn())
|
|
384
|
+
|
|
385
|
+
// Check the result type
|
|
386
|
+
attest<Result<Error, string>>(result)
|
|
387
|
+
|
|
388
|
+
// Check the destructured types
|
|
389
|
+
const [err, value] = result
|
|
390
|
+
attest<Error | undefined>(err)
|
|
391
|
+
attest<string | undefined>(value)
|
|
392
|
+
|
|
393
|
+
// When destructured, the types should be narrowed correctly
|
|
394
|
+
if (err === undefined) {
|
|
395
|
+
attest<string>(value)
|
|
396
|
+
} else {
|
|
397
|
+
attest<undefined>(value)
|
|
398
|
+
}
|
|
399
|
+
})
|
|
370
400
|
})
|
package/src/index.ts
CHANGED
|
@@ -5,54 +5,54 @@ export type Result<E, T> = Success<T> | Failure<E>
|
|
|
5
5
|
export type MaybePromise<T> = T | Promise<T>
|
|
6
6
|
|
|
7
7
|
export function isSuccess<E, T>(result: Result<E, T>): result is Success<T> {
|
|
8
|
-
|
|
8
|
+
return result[0] === undefined
|
|
9
9
|
}
|
|
10
10
|
export function isFailure<E, T>(result: Result<E, T>): result is Failure<E> {
|
|
11
|
-
|
|
11
|
+
return result[0] !== undefined
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function success<T>(value: T): Success<T> {
|
|
15
|
-
|
|
15
|
+
return [undefined, value] as const
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function failure<E>(error: E): Failure<E> {
|
|
19
|
-
|
|
19
|
+
return [error, undefined] as const
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function getErrorMessage(error: unknown): string {
|
|
23
|
-
|
|
23
|
+
if (error === undefined) return 'undefined'
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
if (typeof error === 'string') return error
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
if (
|
|
28
|
+
typeof error === 'object' &&
|
|
29
|
+
error !== null &&
|
|
30
|
+
'message' in error &&
|
|
31
|
+
typeof (error as Record<string, unknown>).message === 'string'
|
|
32
|
+
) {
|
|
33
|
+
return (error as { message: string }).message
|
|
34
|
+
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
try {
|
|
37
|
+
return JSON.stringify(error)
|
|
38
|
+
} catch {
|
|
39
|
+
// fallback in case there's an error stringifying the error
|
|
40
|
+
// with circular references for example.
|
|
41
|
+
return String(error)
|
|
42
|
+
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
function isPromise<T>(value: unknown): value is Promise<T> {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
return (
|
|
47
|
+
typeof value === 'object' &&
|
|
48
|
+
value !== null &&
|
|
49
|
+
'then' in value &&
|
|
50
|
+
typeof (value as { then: unknown }).then === 'function'
|
|
51
|
+
)
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
function isError(value: unknown): value is Error {
|
|
55
|
-
|
|
55
|
+
return value instanceof Error
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|
|
@@ -75,24 +75,26 @@ function isError(value: unknown): value is Error {
|
|
|
75
75
|
* // With a promise
|
|
76
76
|
* const [err, result] = await goTry(fetch('https://api.example.com/data'));
|
|
77
77
|
*/
|
|
78
|
+
export function goTry<T>(fn: () => never): Result<string, never>
|
|
79
|
+
export function goTry<T>(fn: () => Promise<T>): Promise<Result<string, T>>
|
|
78
80
|
export function goTry<T>(promise: Promise<T>): Promise<Result<string, T>>
|
|
79
81
|
export function goTry<T>(fn: () => T): Result<string, T>
|
|
80
82
|
export function goTry<T>(value: T): Result<string, T>
|
|
81
83
|
export function goTry<T>(
|
|
82
|
-
|
|
84
|
+
value: T | Promise<T> | (() => T | Promise<T>),
|
|
83
85
|
): Result<string, T> | Promise<Result<string, T>> {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
86
|
+
try {
|
|
87
|
+
const result =
|
|
88
|
+
typeof value === 'function' ? (value as () => T | Promise<T>)() : value
|
|
89
|
+
if (isPromise<T>(result)) {
|
|
90
|
+
return result
|
|
91
|
+
.then((resolvedValue) => success<T>(resolvedValue))
|
|
92
|
+
.catch((err) => failure<string>(getErrorMessage(err)))
|
|
93
|
+
}
|
|
94
|
+
return success<T>(result)
|
|
95
|
+
} catch (err) {
|
|
96
|
+
return failure<string>(getErrorMessage(err))
|
|
97
|
+
}
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
/**
|
|
@@ -116,37 +118,41 @@ export function goTry<T>(
|
|
|
116
118
|
* // With a promise
|
|
117
119
|
* const [err, result] = await goTryRaw(fetch('https://api.example.com/data'));
|
|
118
120
|
*/
|
|
121
|
+
export function goTryRaw<T, E = Error>(fn: () => never): Result<E, never>
|
|
119
122
|
export function goTryRaw<T, E = Error>(
|
|
120
|
-
|
|
123
|
+
fn: () => Promise<T>,
|
|
124
|
+
): Promise<Result<E, T>>
|
|
125
|
+
export function goTryRaw<T, E = Error>(
|
|
126
|
+
promise: Promise<T>,
|
|
121
127
|
): Promise<Result<E, T>>
|
|
122
128
|
export function goTryRaw<T, E = Error>(fn: () => T): Result<E, T>
|
|
123
129
|
export function goTryRaw<T, E = Error>(value: T): Result<E, T>
|
|
124
130
|
export function goTryRaw<T, E = Error>(
|
|
125
|
-
|
|
131
|
+
value: T | Promise<T> | (() => T | Promise<T>),
|
|
126
132
|
): Result<E, T> | Promise<Result<E, T>> {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
133
|
+
try {
|
|
134
|
+
const result =
|
|
135
|
+
typeof value === 'function' ? (value as () => T | Promise<T>)() : value
|
|
136
|
+
if (isPromise<T>(result)) {
|
|
137
|
+
return result
|
|
138
|
+
.then((resolvedValue) => success<T>(resolvedValue))
|
|
139
|
+
.catch((err) => {
|
|
140
|
+
if (err === undefined) {
|
|
141
|
+
return failure<E>(new Error('undefined') as unknown as E)
|
|
142
|
+
}
|
|
143
|
+
return failure<E>(
|
|
144
|
+
isError(err)
|
|
145
|
+
? (err as unknown as E)
|
|
146
|
+
: (new Error(String(err)) as unknown as E),
|
|
147
|
+
)
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
return success<T>(result)
|
|
151
|
+
} catch (err) {
|
|
152
|
+
return failure<E>(
|
|
153
|
+
isError(err)
|
|
154
|
+
? (err as unknown as E)
|
|
155
|
+
: (new Error(String(err)) as unknown as E),
|
|
156
|
+
)
|
|
157
|
+
}
|
|
152
158
|
}
|