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 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
- "name": "go-go-try",
3
- "version": "6.1.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
- }
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
- 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)
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
- 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')
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
- 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')
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
- 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)
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
- const promise = Promise.reject(new Error('error'))
108
-
109
- // Test with promise that rejects
110
- const result1 = await goTry(promise)
111
- const result2 = await goTryRaw<Error>(promise)
112
-
113
- // Test destructuring
114
- const [err, value] = result1
115
- const [err2, value2] = result2
116
-
117
- // Test type guards
118
- assert.equal(isSuccess(result1), false)
119
- assert.equal(isSuccess(result2), false)
120
- assert.equal(isFailure(result1), true)
121
- assert.equal(isFailure(result2), true)
122
-
123
- // Test values
124
- assert.equal(value, undefined)
125
- assert.equal(value2, undefined)
126
- assert.equal(err, 'error')
127
- assert.equal(typeof err2, 'object')
128
- assert.equal(err2?.message, 'error')
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
- // Test with direct value
133
- const result1 = goTry('value')
134
- const result2 = goTryRaw('value')
135
-
136
- // Test destructuring
137
- const [err1, value] = result1
138
- const [err2, value2] = result2
139
-
140
- // Test values
141
- assert.equal(value, 'value')
142
- assert.equal(value2, 'value')
143
- assert.equal(err1, undefined)
144
- assert.equal(err2, undefined)
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
- // Define an async function
149
- function asyncFn() {
150
- return Promise.resolve(42)
151
- }
152
-
153
- // Test with async function
154
- const result1 = await goTry(asyncFn())
155
- const result2 = await goTryRaw(asyncFn())
156
-
157
- // Test destructuring
158
- const [err1, value] = result1
159
- const [err2, value2] = result2
160
-
161
- // Test values
162
- assert.equal(value, 42)
163
- assert.equal(value2, 42)
164
- assert.equal(err1, undefined)
165
- assert.equal(err2, undefined)
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
- // Define an async function that throws
170
- async function asyncFnThatThrows() {
171
- await 1
172
- throw new Error('async error')
173
- }
174
-
175
- // Test with async function that throws
176
- const result1 = await goTry(asyncFnThatThrows())
177
- const result2 = await goTryRaw(asyncFnThatThrows())
178
-
179
- // Test destructuring
180
- const [err1, value] = result1
181
- const [err2, value2] = result2
182
-
183
- // Test values
184
- assert.equal(value, undefined)
185
- assert.equal(value2, undefined)
186
- assert.equal(err1, 'async error')
187
- assert.equal(typeof err2, 'object')
188
- assert.equal(err2?.message, 'async error')
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
- test('synchronous function returns correct types', () => {
193
- const fn = () => 'value'
194
- const result = goTry(fn)
195
-
196
- // Check the result type
197
- attest<Result<string, string>>(result)
198
-
199
- // Check the destructured types
200
- const [err, value] = result
201
- attest<string | undefined>(err)
202
- attest<string | undefined>(value)
203
-
204
- // When destructured, the types should be narrowed correctly
205
- if (err === undefined) {
206
- attest<string>(value)
207
- } else {
208
- attest<undefined>(value)
209
- }
210
- })
211
-
212
- test('direct value returns correct types', () => {
213
- const result = goTry('value')
214
-
215
- // Check the result type
216
- attest<Result<string, string>>(result)
217
-
218
- // Check the destructured types
219
- const [err, value] = result
220
- attest<string | undefined>(err)
221
- attest<string | undefined>(value)
222
-
223
- // When destructured, the types should be narrowed correctly
224
- if (err === undefined) {
225
- attest<string>(value)
226
- } else {
227
- attest<undefined>(value)
228
- }
229
- })
230
-
231
- test('promise returns correct types', async () => {
232
- const promise = Promise.resolve('value')
233
- const result = await goTry(promise)
234
-
235
- // Check the result type
236
- attest<Result<string, string>>(result)
237
-
238
- // Check the destructured types
239
- const [err, value] = result
240
- attest<string | undefined>(err)
241
- attest<string | undefined>(value)
242
-
243
- // When destructured, the types should be narrowed correctly
244
- if (err === undefined) {
245
- attest<string>(value)
246
- } else {
247
- attest<undefined>(value)
248
- }
249
- })
250
-
251
- test('async function returns correct types', async () => {
252
- const asyncFn = async () => 'value'
253
- const result = await goTry(asyncFn())
254
-
255
- // Check the result type
256
- attest<Result<string, string>>(result)
257
-
258
- // Check the destructured types
259
- const [err, value] = result
260
- attest<string | undefined>(err)
261
- attest<string | undefined>(value)
262
-
263
- // When destructured, the types should be narrowed correctly
264
- if (err === undefined) {
265
- attest<string>(value)
266
- } else {
267
- attest<undefined>(value)
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
- test('type inference works correctly', () => {
274
- const fn = () => 'value'
275
- const result = goTryRaw(fn)
276
-
277
- // Check the result type
278
- attest<Result<Error, string>>(result)
279
-
280
- // Check the destructured types
281
- const [err, value] = result
282
- attest<Error | undefined>(err)
283
- attest<string | undefined>(value)
284
-
285
- // When destructured, the types should be narrowed correctly
286
- if (err === undefined) {
287
- attest<string>(value)
288
- } else {
289
- attest<undefined>(value)
290
- }
291
- })
292
- test('synchronous function returns correct types', () => {
293
- const fn = () => 'value'
294
- const result = goTryRaw(fn)
295
-
296
- // Check the result type
297
- attest<Result<Error, string>>(result)
298
-
299
- // Check the destructured types
300
- const [err, value] = result
301
- attest<Error | undefined>(err)
302
- attest<string | undefined>(value)
303
-
304
- // When destructured, the types should be narrowed correctly
305
- if (err === undefined) {
306
- attest<string>(value)
307
- } else {
308
- attest<undefined>(value)
309
- }
310
- })
311
-
312
- test('direct value returns correct types', () => {
313
- const result = goTryRaw('value')
314
-
315
- // Check the result type
316
- attest<Result<Error, string>>(result)
317
-
318
- // Check the destructured types
319
- const [err, value] = result
320
- attest<Error | undefined>(err)
321
- attest<string | undefined>(value)
322
-
323
- // When destructured, the types should be narrowed correctly
324
- if (err === undefined) {
325
- attest<string>(value)
326
- } else {
327
- attest<undefined>(value)
328
- }
329
- })
330
-
331
- test('promise returns correct types', async () => {
332
- const promise = Promise.resolve('value')
333
- const result = await goTryRaw(promise)
334
-
335
- // Check the result type
336
- attest<Result<Error, string>>(result)
337
-
338
- // Check the destructured types
339
- const [err, value] = result
340
- attest<Error | undefined>(err)
341
- attest<string | undefined>(value)
342
-
343
- // When destructured, the types should be narrowed correctly
344
- if (err === undefined) {
345
- attest<string>(value)
346
- } else {
347
- attest<undefined>(value)
348
- }
349
- })
350
-
351
- test('async function returns correct types', async () => {
352
- const asyncFn = async () => 'value'
353
- const result = await goTryRaw(asyncFn())
354
-
355
- // Check the result type
356
- attest<Result<Error, string>>(result)
357
-
358
- // Check the destructured types
359
- const [err, value] = result
360
- attest<Error | undefined>(err)
361
- attest<string | undefined>(value)
362
-
363
- // When destructured, the types should be narrowed correctly
364
- if (err === undefined) {
365
- attest<string>(value)
366
- } else {
367
- attest<undefined>(value)
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
- return result[0] === undefined
8
+ return result[0] === undefined
9
9
  }
10
10
  export function isFailure<E, T>(result: Result<E, T>): result is Failure<E> {
11
- return result[0] !== undefined
11
+ return result[0] !== undefined
12
12
  }
13
13
 
14
14
  export function success<T>(value: T): Success<T> {
15
- return [undefined, value] as const
15
+ return [undefined, value] as const
16
16
  }
17
17
 
18
18
  export function failure<E>(error: E): Failure<E> {
19
- return [error, undefined] as const
19
+ return [error, undefined] as const
20
20
  }
21
21
 
22
22
  function getErrorMessage(error: unknown): string {
23
- if (error === undefined) return 'undefined'
23
+ if (error === undefined) return 'undefined'
24
24
 
25
- if (typeof error === 'string') return error
25
+ if (typeof error === 'string') return error
26
26
 
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
- }
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
- 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
- }
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
- return (
47
- typeof value === 'object' &&
48
- value !== null &&
49
- 'then' in value &&
50
- typeof (value as { then: unknown }).then === 'function'
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
- return value instanceof Error
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
- value: T | Promise<T> | (() => T | Promise<T>),
84
+ value: T | Promise<T> | (() => T | Promise<T>),
83
85
  ): Result<string, T> | Promise<Result<string, T>> {
84
- try {
85
- const result =
86
- typeof value === 'function' ? (value as () => T | Promise<T>)() : value
87
- if (isPromise<T>(result)) {
88
- return result
89
- .then((resolvedValue) => success<T>(resolvedValue))
90
- .catch((err) => failure<string>(getErrorMessage(err)))
91
- }
92
- return success<T>(result)
93
- } catch (err) {
94
- return failure<string>(getErrorMessage(err))
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
- promise: Promise<T>,
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
- value: T | Promise<T> | (() => T | Promise<T>),
131
+ value: T | Promise<T> | (() => T | Promise<T>),
126
132
  ): Result<E, T> | Promise<Result<E, T>> {
127
- try {
128
- const result =
129
- typeof value === 'function' ? (value as () => T | Promise<T>)() : value
130
- if (isPromise<T>(result)) {
131
- return result
132
- .then((resolvedValue) => success<T>(resolvedValue))
133
- .catch((err) => {
134
- if (err === undefined) {
135
- return failure<E>(new Error('undefined') as unknown as E)
136
- }
137
- return failure<E>(
138
- isError(err)
139
- ? (err as unknown as E)
140
- : (new Error(String(err)) as unknown as E),
141
- )
142
- })
143
- }
144
- return success<T>(result)
145
- } catch (err) {
146
- return failure<E>(
147
- isError(err)
148
- ? (err as unknown as E)
149
- : (new Error(String(err)) as unknown as E),
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
  }