@wentools/result 0.1.2-beta.94ae1942
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/LICENSE +21 -0
- package/README.md +146 -0
- package/esm/err/err.d.ts +38 -0
- package/esm/err/err.d.ts.map +1 -0
- package/esm/err/err.js +38 -0
- package/esm/err/mod.d.ts +2 -0
- package/esm/err/mod.d.ts.map +1 -0
- package/esm/err/mod.js +1 -0
- package/esm/is_result/is_result.d.ts +11 -0
- package/esm/is_result/is_result.d.ts.map +1 -0
- package/esm/is_result/is_result.js +14 -0
- package/esm/is_result/mod.d.ts +2 -0
- package/esm/is_result/mod.d.ts.map +1 -0
- package/esm/is_result/mod.js +1 -0
- package/esm/mod.d.ts +156 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +65 -0
- package/esm/package.json +3 -0
- package/esm/propagate_err/mod.d.ts +2 -0
- package/esm/propagate_err/mod.d.ts.map +1 -0
- package/esm/propagate_err/mod.js +1 -0
- package/esm/propagate_err/propagate_err.d.ts +28 -0
- package/esm/propagate_err/propagate_err.d.ts.map +1 -0
- package/esm/propagate_err/propagate_err.js +30 -0
- package/package.json +33 -0
- package/script/err/err.d.ts +38 -0
- package/script/err/err.d.ts.map +1 -0
- package/script/err/err.js +41 -0
- package/script/err/mod.d.ts +2 -0
- package/script/err/mod.d.ts.map +1 -0
- package/script/err/mod.js +5 -0
- package/script/is_result/is_result.d.ts +11 -0
- package/script/is_result/is_result.d.ts.map +1 -0
- package/script/is_result/is_result.js +17 -0
- package/script/is_result/mod.d.ts +2 -0
- package/script/is_result/mod.d.ts.map +1 -0
- package/script/is_result/mod.js +5 -0
- package/script/mod.d.ts +156 -0
- package/script/mod.d.ts.map +1 -0
- package/script/mod.js +77 -0
- package/script/package.json +3 -0
- package/script/propagate_err/mod.d.ts +2 -0
- package/script/propagate_err/mod.d.ts.map +1 -0
- package/script/propagate_err/mod.js +5 -0
- package/script/propagate_err/propagate_err.d.ts +28 -0
- package/script/propagate_err/propagate_err.d.ts.map +1 -0
- package/script/propagate_err/propagate_err.js +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wentools
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @wentools/result
|
|
2
|
+
|
|
3
|
+
A TypeScript-first wrapper around [neverthrow](https://github.com/supermacro/neverthrow) that adds literal type inference and error composition patterns.
|
|
4
|
+
|
|
5
|
+
## Why This Exists
|
|
6
|
+
|
|
7
|
+
neverthrow is excellent for Result-based error handling, but creating typed errors requires boilerplate:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// With plain neverthrow
|
|
11
|
+
import { err } from 'neverthrow'
|
|
12
|
+
|
|
13
|
+
// You need `as const` or explicit types to preserve the literal
|
|
14
|
+
const result = err({ type: 'not_found' as const, message: 'User not found' })
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This library fixes that with TypeScript 5.0+ const type parameters:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// With @wentools/result
|
|
21
|
+
import { err } from '@wentools/result'
|
|
22
|
+
|
|
23
|
+
// Literal type is inferred automatically
|
|
24
|
+
const result = err('not_found', 'User not found')
|
|
25
|
+
// Type: Err<never, { type: 'not_found'; message: string }>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
It also provides utilities for:
|
|
29
|
+
- Defining error types concisely
|
|
30
|
+
- Extracting and composing error types from functions
|
|
31
|
+
- Runtime Result detection without importing neverthrow types
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# JSR (recommended)
|
|
37
|
+
npx jsr add @wentools/result
|
|
38
|
+
|
|
39
|
+
# Deno
|
|
40
|
+
deno add jsr:@wentools/result
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### Basic Error Creation
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { err, ok, type Result, type ErrorType } from '@wentools/result'
|
|
49
|
+
|
|
50
|
+
// Define error types concisely
|
|
51
|
+
type UserNotFoundError = ErrorType<'user_not_found'>
|
|
52
|
+
type InvalidEmailError = ErrorType<'invalid_email', { email: string }>
|
|
53
|
+
|
|
54
|
+
// Create Results with inferred literal types
|
|
55
|
+
const getUser = (id: string): Result<User, UserNotFoundError> => {
|
|
56
|
+
const user = users.get(id)
|
|
57
|
+
if (!user) {
|
|
58
|
+
return err('user_not_found', `User ${id} not found`)
|
|
59
|
+
}
|
|
60
|
+
return ok(user)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Add context to errors
|
|
64
|
+
const validateEmail = (email: string): Result<string, InvalidEmailError> => {
|
|
65
|
+
if (!email.includes('@')) {
|
|
66
|
+
return err('invalid_email', 'Email must contain @', { email })
|
|
67
|
+
}
|
|
68
|
+
return ok(email)
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Async Chains
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { errAsync, okAsync, type ResultAsync } from '@wentools/result'
|
|
76
|
+
|
|
77
|
+
const createUser = (data: UserData): ResultAsync<User, CreateError> => {
|
|
78
|
+
return validateEmail(data.email)
|
|
79
|
+
.asyncAndThen((email) =>
|
|
80
|
+
checkEmailUnique(email)
|
|
81
|
+
.andThen(() => insertUser({ ...data, email }))
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Error Type Composition
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { type ExtractFnError } from '@wentools/result'
|
|
90
|
+
|
|
91
|
+
// Extract and combine error types from multiple functions
|
|
92
|
+
type ServiceError =
|
|
93
|
+
| ExtractFnError<typeof getUser>
|
|
94
|
+
| ExtractFnError<typeof validateEmail>
|
|
95
|
+
| ExtractFnError<typeof createUser>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Runtime Type Check
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { isResult } from '@wentools/result'
|
|
102
|
+
|
|
103
|
+
const handle = (value: unknown) => {
|
|
104
|
+
if (isResult(value)) {
|
|
105
|
+
if (value.isErr()) {
|
|
106
|
+
console.error(value.error)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## API
|
|
113
|
+
|
|
114
|
+
### Functions
|
|
115
|
+
|
|
116
|
+
| Function | Description |
|
|
117
|
+
|----------|-------------|
|
|
118
|
+
| `err(type, message, additional?)` | Create an Err with literal type inference |
|
|
119
|
+
| `errAsync(type, message, additional?)` | Async version of `err` |
|
|
120
|
+
| `ok(value)` | Create an Ok (re-export from neverthrow) |
|
|
121
|
+
| `okAsync(value)` | Create an async Ok (re-export from neverthrow) |
|
|
122
|
+
| `makeErr(type, message, additional?)` | Create error object without wrapping in Err |
|
|
123
|
+
| `rawErr(error)` | Direct neverthrow `err()` for lifting unstructured errors |
|
|
124
|
+
| `isResult(value)` | Runtime check if value is a Result |
|
|
125
|
+
| `propagateErr(result)` | Propagate error to different Result type |
|
|
126
|
+
|
|
127
|
+
### Types
|
|
128
|
+
|
|
129
|
+
| Type | Description |
|
|
130
|
+
|------|-------------|
|
|
131
|
+
| `Result<T, E>` | Sync Result (from neverthrow) |
|
|
132
|
+
| `ResultAsync<T, E>` | Async Result (from neverthrow) |
|
|
133
|
+
| `ErrorType<Type, Additional?>` | Utility for defining `{ type, message, ...additional }` |
|
|
134
|
+
| `ExtractError<T>` | Extract error type from Result or Promise<Result> |
|
|
135
|
+
| `ExtractFnError<F>` | Extract error type from function return type |
|
|
136
|
+
| `ExtractErrors<T[]>` | Union of errors from multiple Results |
|
|
137
|
+
| `ExtractFnsError<F[]>` | Union of errors from multiple functions |
|
|
138
|
+
|
|
139
|
+
## Requirements
|
|
140
|
+
|
|
141
|
+
- TypeScript 5.0+ (for const type parameters)
|
|
142
|
+
- neverthrow 8.x (peer dependency)
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|
package/esm/err/err.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type Err } from 'neverthrow';
|
|
2
|
+
/**
|
|
3
|
+
* Create an Err Result with automatic literal type preservation
|
|
4
|
+
*
|
|
5
|
+
* Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
|
|
6
|
+
* No need for 'as const' - the type parameter is inferred as a literal!
|
|
7
|
+
*
|
|
8
|
+
* Returns Err<never, E> (not Result<never, E>) so .error is directly accessible.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // ✅ Simple error
|
|
12
|
+
* return err('not_found', 'User not found')
|
|
13
|
+
* // Type: Err<never, { type: 'not_found', message: string }>
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // ✅ Error with additional properties
|
|
17
|
+
* return err('not_found', 'User not found', { userId: '123' })
|
|
18
|
+
* // Type: Err<never, { type: 'not_found', message: string, userId: string }>
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* // ✅ Direct .error access (no narrowing needed)
|
|
22
|
+
* const error = err('not_found', 'User not found').error
|
|
23
|
+
* // error.type is 'not_found'
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // ✅ Error with complex additional data
|
|
27
|
+
* return err('validation_failed', 'Invalid input', {
|
|
28
|
+
* field: 'email',
|
|
29
|
+
* errors: ['Invalid format']
|
|
30
|
+
* })
|
|
31
|
+
* // Type: Err<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
|
|
32
|
+
*/
|
|
33
|
+
declare const err: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => Err<never, {
|
|
34
|
+
type: TType;
|
|
35
|
+
message: string;
|
|
36
|
+
} & TAdditional>;
|
|
37
|
+
export { err };
|
|
38
|
+
//# sourceMappingURL=err.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"err.d.ts","sourceRoot":"","sources":["../../src/err/err.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,GAAG,EAAE,MAAM,YAAY,CAAA;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,QAAA,MAAM,GAAG,GACR,KAAK,CAAC,KAAK,SAAS,MAAM,EAC1B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEnE,MAAM,KAAK,EACX,SAAS,MAAM,EACf,aAAa,WAAW,KACtB,GAAG,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,CAKP,CAAA;AAErD,OAAO,EAAE,GAAG,EAAE,CAAA"}
|
package/esm/err/err.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { err as _Err } from 'neverthrow';
|
|
2
|
+
/**
|
|
3
|
+
* Create an Err Result with automatic literal type preservation
|
|
4
|
+
*
|
|
5
|
+
* Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
|
|
6
|
+
* No need for 'as const' - the type parameter is inferred as a literal!
|
|
7
|
+
*
|
|
8
|
+
* Returns Err<never, E> (not Result<never, E>) so .error is directly accessible.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // ✅ Simple error
|
|
12
|
+
* return err('not_found', 'User not found')
|
|
13
|
+
* // Type: Err<never, { type: 'not_found', message: string }>
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // ✅ Error with additional properties
|
|
17
|
+
* return err('not_found', 'User not found', { userId: '123' })
|
|
18
|
+
* // Type: Err<never, { type: 'not_found', message: string, userId: string }>
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* // ✅ Direct .error access (no narrowing needed)
|
|
22
|
+
* const error = err('not_found', 'User not found').error
|
|
23
|
+
* // error.type is 'not_found'
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // ✅ Error with complex additional data
|
|
27
|
+
* return err('validation_failed', 'Invalid input', {
|
|
28
|
+
* field: 'email',
|
|
29
|
+
* errors: ['Invalid format']
|
|
30
|
+
* })
|
|
31
|
+
* // Type: Err<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
|
|
32
|
+
*/
|
|
33
|
+
const err = (type, message, additional) => _Err({
|
|
34
|
+
...additional,
|
|
35
|
+
type,
|
|
36
|
+
message,
|
|
37
|
+
});
|
|
38
|
+
export { err };
|
package/esm/err/mod.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/err/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA"}
|
package/esm/err/mod.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { err } from './err.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a value is a neverthrow Result type
|
|
3
|
+
*
|
|
4
|
+
* Uses duck typing to detect Result objects without importing neverthrow types.
|
|
5
|
+
*/
|
|
6
|
+
declare const isResult: (value: unknown) => value is {
|
|
7
|
+
isOk: () => boolean;
|
|
8
|
+
isErr: () => boolean;
|
|
9
|
+
};
|
|
10
|
+
export { isResult };
|
|
11
|
+
//# sourceMappingURL=is_result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is_result.d.ts","sourceRoot":"","sources":["../../src/is_result/is_result.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,QAAA,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI;IAAE,IAAI,EAAE,MAAM,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,OAAO,CAAA;CAStF,CAAA;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a value is a neverthrow Result type
|
|
3
|
+
*
|
|
4
|
+
* Uses duck typing to detect Result objects without importing neverthrow types.
|
|
5
|
+
*/
|
|
6
|
+
const isResult = (value) => {
|
|
7
|
+
return (value !== null &&
|
|
8
|
+
typeof value === 'object' &&
|
|
9
|
+
'isOk' in value &&
|
|
10
|
+
'isErr' in value &&
|
|
11
|
+
typeof value.isOk === 'function' &&
|
|
12
|
+
typeof value.isErr === 'function');
|
|
13
|
+
};
|
|
14
|
+
export { isResult };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/is_result/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { isResult } from './is_result.js';
|
package/esm/mod.d.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { err as _Err, ok, type Result, type Err, ResultAsync, okAsync as neverthrowOkAsync } from 'neverthrow';
|
|
2
|
+
/**
|
|
3
|
+
* Create an error object with literal type preservation
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const error = makeErr('not_found', 'User not found')
|
|
7
|
+
* // ✅ Type: { type: 'not_found', message: string }
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const error = makeErr('not_found', 'User not found', { userId: '123' })
|
|
11
|
+
* // ✅ Type: { type: 'not_found', message: string, userId: string }
|
|
12
|
+
*/
|
|
13
|
+
declare const makeErr: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => {
|
|
14
|
+
type: TType;
|
|
15
|
+
message: string;
|
|
16
|
+
} & TAdditional;
|
|
17
|
+
/**
|
|
18
|
+
* Create an async Err ResultAsync with automatic literal type preservation
|
|
19
|
+
*
|
|
20
|
+
* Async version of err() - same signature, returns ResultAsync instead of Result.
|
|
21
|
+
* Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // ✅ Simple error
|
|
25
|
+
* return errAsync('not_found', 'User not found')
|
|
26
|
+
* // Type: ResultAsync<never, { type: 'not_found', message: string }>
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // ✅ Error with additional properties
|
|
30
|
+
* return errAsync('not_found', 'User not found', { userId: '123' })
|
|
31
|
+
* // Type: ResultAsync<never, { type: 'not_found', message: string, userId: string }>
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // ✅ Error with complex additional data
|
|
35
|
+
* return errAsync('validation_failed', 'Invalid input', {
|
|
36
|
+
* field: 'email',
|
|
37
|
+
* errors: ['Invalid format']
|
|
38
|
+
* })
|
|
39
|
+
* // Type: ResultAsync<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
|
|
40
|
+
*/
|
|
41
|
+
declare const errAsync: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => ResultAsync<never, {
|
|
42
|
+
type: TType;
|
|
43
|
+
message: string;
|
|
44
|
+
} & TAdditional>;
|
|
45
|
+
/**
|
|
46
|
+
* Re-export okAsync from neverthrow for consistency
|
|
47
|
+
* Creates a successful ResultAsync
|
|
48
|
+
*/
|
|
49
|
+
declare const okAsync: typeof neverthrowOkAsync;
|
|
50
|
+
/**
|
|
51
|
+
* Utility type for defining error types concisely
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* // Instead of:
|
|
55
|
+
* type UserNotFoundError = {
|
|
56
|
+
* type: 'user_not_found'
|
|
57
|
+
* message: string
|
|
58
|
+
* userId: UserId
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* // Write:
|
|
62
|
+
* type UserNotFoundError = ErrorType<'user_not_found', { userId: UserId }>
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* // Error without additional properties:
|
|
66
|
+
* type InvalidOperationError = ErrorType<'invalid_operation'>
|
|
67
|
+
*/
|
|
68
|
+
type ErrorType<TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>> = {
|
|
69
|
+
type: TType;
|
|
70
|
+
message: string;
|
|
71
|
+
} & TAdditional;
|
|
72
|
+
/**
|
|
73
|
+
* Extract the error type from a Result or Promise<Result>
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // From async function
|
|
77
|
+
* const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
|
|
78
|
+
* type GetUserError = ExtractError<ReturnType<typeof getUser>>
|
|
79
|
+
* // Type: UserNotFoundError
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* // From Result type directly
|
|
83
|
+
* type MyResult = Result<User, InvalidError>
|
|
84
|
+
* type MyError = ExtractError<MyResult>
|
|
85
|
+
* // Type: InvalidError
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* // Works with composed errors
|
|
89
|
+
* const replaceVersion = async (): Promise<Result<Version, VersionNotFoundError | VersionExistsError>> => { ... }
|
|
90
|
+
* type ReplaceError = ExtractError<ReturnType<typeof replaceVersion>>
|
|
91
|
+
* // Type: VersionNotFoundError | VersionExistsError
|
|
92
|
+
*/
|
|
93
|
+
type ExtractError<TResultOrPromise> = TResultOrPromise extends Promise<Result<unknown, infer TError>> ? TError : TResultOrPromise extends Result<unknown, infer TError> ? TError : never;
|
|
94
|
+
/**
|
|
95
|
+
* Extract the error type from a function that returns Result or Promise<Result>
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* // Simple extraction
|
|
99
|
+
* const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
|
|
100
|
+
* type GetUserError = ExtractFnError<typeof getUser>
|
|
101
|
+
* // Type: UserNotFoundError
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* // Compose errors from multiple functions
|
|
105
|
+
* const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
|
|
106
|
+
* const getImage = async (id: string): Promise<Result<Image, ImageNotFoundError>> => { ... }
|
|
107
|
+
* type CombinedError = ExtractFnError<typeof getUser> | ExtractFnError<typeof getImage>
|
|
108
|
+
* // Type: UserNotFoundError | ImageNotFoundError
|
|
109
|
+
*/
|
|
110
|
+
type ExtractFnError<TFunction extends (...args: unknown[]) => unknown> = ExtractError<ReturnType<TFunction>>;
|
|
111
|
+
/**
|
|
112
|
+
* Extract and combine error types from multiple Result or Promise<Result> types
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* type UserResult = Result<User, UserNotFoundError>
|
|
116
|
+
* type ImageResult = Promise<Result<Image, ImageNotFoundError>>
|
|
117
|
+
* type ProductResult = Result<Product, ProductNotFoundError>
|
|
118
|
+
*
|
|
119
|
+
* type CombinedError = ExtractErrors<[UserResult, ImageResult, ProductResult]>
|
|
120
|
+
* // Type: UserNotFoundError | ImageNotFoundError | ProductNotFoundError
|
|
121
|
+
*/
|
|
122
|
+
type ExtractErrors<TResults extends readonly unknown[]> = TResults extends readonly [
|
|
123
|
+
infer TFirst,
|
|
124
|
+
...infer TRest
|
|
125
|
+
] ? ExtractError<TFirst> | ExtractErrors<TRest> : never;
|
|
126
|
+
/**
|
|
127
|
+
* Extract and combine error types from multiple functions that return Result or Promise<Result>
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
|
|
131
|
+
* const getImage = async (id: string): Promise<Result<Image, ImageNotFoundError>> => { ... }
|
|
132
|
+
* const deleteProduct = async (id: string): Promise<Result<void, ProductNotFoundError>> => { ... }
|
|
133
|
+
*
|
|
134
|
+
* type CombinedError = ExtractFnsError<[typeof getUser, typeof getImage, typeof deleteProduct]>
|
|
135
|
+
* // Type: UserNotFoundError | ImageNotFoundError | ProductNotFoundError
|
|
136
|
+
*/
|
|
137
|
+
type ExtractFnsError<TFunctions extends readonly ((...args: unknown[]) => unknown)[]> = TFunctions extends readonly [
|
|
138
|
+
infer TFirst,
|
|
139
|
+
...infer TRest extends readonly ((...args: unknown[]) => unknown)[]
|
|
140
|
+
] ? ExtractFnError<TFirst & ((...args: unknown[]) => unknown)> | ExtractFnsError<TRest> : never;
|
|
141
|
+
/**
|
|
142
|
+
* Raw error function from neverthrow - use for lifting database errors directly
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* const seedResult = await songSeeds.get.one.byId(songSeedId)
|
|
146
|
+
* if (seedResult.isErr()) {
|
|
147
|
+
* return rawErr(seedResult.error)
|
|
148
|
+
* }
|
|
149
|
+
*/
|
|
150
|
+
declare const rawErr: typeof _Err;
|
|
151
|
+
export { makeErr, errAsync, ok, okAsync, rawErr, _Err, ResultAsync };
|
|
152
|
+
export type { Result, Err, ErrorType, ExtractError, ExtractFnError, ExtractErrors, ExtractFnsError };
|
|
153
|
+
export { err } from './err/mod.js';
|
|
154
|
+
export { isResult } from './is_result/mod.js';
|
|
155
|
+
export { propagateErr } from './propagate_err/mod.js';
|
|
156
|
+
//# sourceMappingURL=mod.d.ts.map
|
package/esm/mod.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"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"}
|
package/esm/mod.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { err as _Err, ok, ResultAsync, errAsync as neverthrowErrAsync, okAsync as neverthrowOkAsync, } from 'neverthrow';
|
|
2
|
+
/**
|
|
3
|
+
* Create an error object with literal type preservation
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const error = makeErr('not_found', 'User not found')
|
|
7
|
+
* // ✅ Type: { type: 'not_found', message: string }
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const error = makeErr('not_found', 'User not found', { userId: '123' })
|
|
11
|
+
* // ✅ Type: { type: 'not_found', message: string, userId: string }
|
|
12
|
+
*/
|
|
13
|
+
const makeErr = (type, message, additional) => ({
|
|
14
|
+
...additional,
|
|
15
|
+
type,
|
|
16
|
+
message,
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Create an async Err ResultAsync with automatic literal type preservation
|
|
20
|
+
*
|
|
21
|
+
* Async version of err() - same signature, returns ResultAsync instead of Result.
|
|
22
|
+
* Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // ✅ Simple error
|
|
26
|
+
* return errAsync('not_found', 'User not found')
|
|
27
|
+
* // Type: ResultAsync<never, { type: 'not_found', message: string }>
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* // ✅ Error with additional properties
|
|
31
|
+
* return errAsync('not_found', 'User not found', { userId: '123' })
|
|
32
|
+
* // Type: ResultAsync<never, { type: 'not_found', message: string, userId: string }>
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // ✅ Error with complex additional data
|
|
36
|
+
* return errAsync('validation_failed', 'Invalid input', {
|
|
37
|
+
* field: 'email',
|
|
38
|
+
* errors: ['Invalid format']
|
|
39
|
+
* })
|
|
40
|
+
* // Type: ResultAsync<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
|
|
41
|
+
*/
|
|
42
|
+
const errAsync = (type, message, additional) => neverthrowErrAsync({
|
|
43
|
+
...additional,
|
|
44
|
+
type,
|
|
45
|
+
message,
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* Re-export okAsync from neverthrow for consistency
|
|
49
|
+
* Creates a successful ResultAsync
|
|
50
|
+
*/
|
|
51
|
+
const okAsync = neverthrowOkAsync;
|
|
52
|
+
/**
|
|
53
|
+
* Raw error function from neverthrow - use for lifting database errors directly
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* const seedResult = await songSeeds.get.one.byId(songSeedId)
|
|
57
|
+
* if (seedResult.isErr()) {
|
|
58
|
+
* return rawErr(seedResult.error)
|
|
59
|
+
* }
|
|
60
|
+
*/
|
|
61
|
+
const rawErr = _Err;
|
|
62
|
+
export { makeErr, errAsync, ok, okAsync, rawErr, _Err, ResultAsync };
|
|
63
|
+
export { err } from './err/mod.js';
|
|
64
|
+
export { isResult } from './is_result/mod.js';
|
|
65
|
+
export { propagateErr } from './propagate_err/mod.js';
|
package/esm/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/propagate_err/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { propagateErr } from './propagate_err.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Result } from 'neverthrow';
|
|
2
|
+
/**
|
|
3
|
+
* Propagates an error Result to a different success type context.
|
|
4
|
+
*
|
|
5
|
+
* This is safe because error Results never contain the success value - only the error.
|
|
6
|
+
* TypeScript's structural typing prevents direct assignment of Result<T, E> to Result<U, E>
|
|
7
|
+
* even though the error type is identical and we're in the error branch.
|
|
8
|
+
*
|
|
9
|
+
* Common use case: Early return from a function that creates multiple items. If creating
|
|
10
|
+
* item 2 fails with Result<Item, DatabaseError>, we need to return Result<Item[], DatabaseError>.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const result = await createUser(db, data) // Result<User, DatabaseError>
|
|
14
|
+
* if (result.isErr()) {
|
|
15
|
+
* // Need to return Result<Profile, DatabaseError> but have Result<User, DatabaseError>
|
|
16
|
+
* return propagateErr(result)
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // In bulk creation, propagate single-item error to array context
|
|
21
|
+
* const itemResult = await createItem(data) // Result<Item, Error>
|
|
22
|
+
* if (itemResult.isErr()) {
|
|
23
|
+
* return propagateErr<Item[], Error>(itemResult) // Result<Item[], Error>
|
|
24
|
+
* }
|
|
25
|
+
*/
|
|
26
|
+
declare const propagateErr: <TNew, E>(errorResult: Result<unknown, E>) => Result<TNew, E>;
|
|
27
|
+
export { propagateErr };
|
|
28
|
+
//# sourceMappingURL=propagate_err.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propagate_err.d.ts","sourceRoot":"","sources":["../../src/propagate_err/propagate_err.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,YAAY,GAAI,IAAI,EAAE,CAAC,EAAE,aAAa,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,KAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAI9E,CAAA;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Propagates an error Result to a different success type context.
|
|
3
|
+
*
|
|
4
|
+
* This is safe because error Results never contain the success value - only the error.
|
|
5
|
+
* TypeScript's structural typing prevents direct assignment of Result<T, E> to Result<U, E>
|
|
6
|
+
* even though the error type is identical and we're in the error branch.
|
|
7
|
+
*
|
|
8
|
+
* Common use case: Early return from a function that creates multiple items. If creating
|
|
9
|
+
* item 2 fails with Result<Item, DatabaseError>, we need to return Result<Item[], DatabaseError>.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const result = await createUser(db, data) // Result<User, DatabaseError>
|
|
13
|
+
* if (result.isErr()) {
|
|
14
|
+
* // Need to return Result<Profile, DatabaseError> but have Result<User, DatabaseError>
|
|
15
|
+
* return propagateErr(result)
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // In bulk creation, propagate single-item error to array context
|
|
20
|
+
* const itemResult = await createItem(data) // Result<Item, Error>
|
|
21
|
+
* if (itemResult.isErr()) {
|
|
22
|
+
* return propagateErr<Item[], Error>(itemResult) // Result<Item[], Error>
|
|
23
|
+
* }
|
|
24
|
+
*/
|
|
25
|
+
const propagateErr = (errorResult) => {
|
|
26
|
+
// Type assertion is safe: we're only propagating errors, and error Results
|
|
27
|
+
// don't contain the success value. The error type E is preserved exactly.
|
|
28
|
+
return errorResult;
|
|
29
|
+
};
|
|
30
|
+
export { propagateErr };
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wentools/result",
|
|
3
|
+
"version": "0.1.2-beta.94ae1942",
|
|
4
|
+
"description": "TypeScript-first Result type with literal error inference",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"result",
|
|
7
|
+
"neverthrow",
|
|
8
|
+
"typescript",
|
|
9
|
+
"error-handling",
|
|
10
|
+
"type-safe"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://gitlab.com/wentools/result"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"main": "./script/mod.js",
|
|
18
|
+
"module": "./esm/mod.js",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": "./esm/mod.js",
|
|
22
|
+
"require": "./script/mod.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"scripts": {},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"neverthrow": "^8.2.0"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"neverthrow": "^8.2.0"
|
|
31
|
+
},
|
|
32
|
+
"_generatedBy": "dnt@dev"
|
|
33
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type Err } from 'neverthrow';
|
|
2
|
+
/**
|
|
3
|
+
* Create an Err Result with automatic literal type preservation
|
|
4
|
+
*
|
|
5
|
+
* Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
|
|
6
|
+
* No need for 'as const' - the type parameter is inferred as a literal!
|
|
7
|
+
*
|
|
8
|
+
* Returns Err<never, E> (not Result<never, E>) so .error is directly accessible.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // ✅ Simple error
|
|
12
|
+
* return err('not_found', 'User not found')
|
|
13
|
+
* // Type: Err<never, { type: 'not_found', message: string }>
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // ✅ Error with additional properties
|
|
17
|
+
* return err('not_found', 'User not found', { userId: '123' })
|
|
18
|
+
* // Type: Err<never, { type: 'not_found', message: string, userId: string }>
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* // ✅ Direct .error access (no narrowing needed)
|
|
22
|
+
* const error = err('not_found', 'User not found').error
|
|
23
|
+
* // error.type is 'not_found'
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // ✅ Error with complex additional data
|
|
27
|
+
* return err('validation_failed', 'Invalid input', {
|
|
28
|
+
* field: 'email',
|
|
29
|
+
* errors: ['Invalid format']
|
|
30
|
+
* })
|
|
31
|
+
* // Type: Err<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
|
|
32
|
+
*/
|
|
33
|
+
declare const err: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => Err<never, {
|
|
34
|
+
type: TType;
|
|
35
|
+
message: string;
|
|
36
|
+
} & TAdditional>;
|
|
37
|
+
export { err };
|
|
38
|
+
//# sourceMappingURL=err.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"err.d.ts","sourceRoot":"","sources":["../../src/err/err.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,GAAG,EAAE,MAAM,YAAY,CAAA;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,QAAA,MAAM,GAAG,GACR,KAAK,CAAC,KAAK,SAAS,MAAM,EAC1B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEnE,MAAM,KAAK,EACX,SAAS,MAAM,EACf,aAAa,WAAW,KACtB,GAAG,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,CAKP,CAAA;AAErD,OAAO,EAAE,GAAG,EAAE,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.err = void 0;
|
|
4
|
+
const neverthrow_1 = require("neverthrow");
|
|
5
|
+
/**
|
|
6
|
+
* Create an Err Result with automatic literal type preservation
|
|
7
|
+
*
|
|
8
|
+
* Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
|
|
9
|
+
* No need for 'as const' - the type parameter is inferred as a literal!
|
|
10
|
+
*
|
|
11
|
+
* Returns Err<never, E> (not Result<never, E>) so .error is directly accessible.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // ✅ Simple error
|
|
15
|
+
* return err('not_found', 'User not found')
|
|
16
|
+
* // Type: Err<never, { type: 'not_found', message: string }>
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // ✅ Error with additional properties
|
|
20
|
+
* return err('not_found', 'User not found', { userId: '123' })
|
|
21
|
+
* // Type: Err<never, { type: 'not_found', message: string, userId: string }>
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // ✅ Direct .error access (no narrowing needed)
|
|
25
|
+
* const error = err('not_found', 'User not found').error
|
|
26
|
+
* // error.type is 'not_found'
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // ✅ Error with complex additional data
|
|
30
|
+
* return err('validation_failed', 'Invalid input', {
|
|
31
|
+
* field: 'email',
|
|
32
|
+
* errors: ['Invalid format']
|
|
33
|
+
* })
|
|
34
|
+
* // Type: Err<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
|
|
35
|
+
*/
|
|
36
|
+
const err = (type, message, additional) => (0, neverthrow_1.err)({
|
|
37
|
+
...additional,
|
|
38
|
+
type,
|
|
39
|
+
message,
|
|
40
|
+
});
|
|
41
|
+
exports.err = err;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/err/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a value is a neverthrow Result type
|
|
3
|
+
*
|
|
4
|
+
* Uses duck typing to detect Result objects without importing neverthrow types.
|
|
5
|
+
*/
|
|
6
|
+
declare const isResult: (value: unknown) => value is {
|
|
7
|
+
isOk: () => boolean;
|
|
8
|
+
isErr: () => boolean;
|
|
9
|
+
};
|
|
10
|
+
export { isResult };
|
|
11
|
+
//# sourceMappingURL=is_result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is_result.d.ts","sourceRoot":"","sources":["../../src/is_result/is_result.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,QAAA,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI;IAAE,IAAI,EAAE,MAAM,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,OAAO,CAAA;CAStF,CAAA;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Check if a value is a neverthrow Result type
|
|
4
|
+
*
|
|
5
|
+
* Uses duck typing to detect Result objects without importing neverthrow types.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.isResult = void 0;
|
|
9
|
+
const isResult = (value) => {
|
|
10
|
+
return (value !== null &&
|
|
11
|
+
typeof value === 'object' &&
|
|
12
|
+
'isOk' in value &&
|
|
13
|
+
'isErr' in value &&
|
|
14
|
+
typeof value.isOk === 'function' &&
|
|
15
|
+
typeof value.isErr === 'function');
|
|
16
|
+
};
|
|
17
|
+
exports.isResult = isResult;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/is_result/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isResult = void 0;
|
|
4
|
+
var is_result_js_1 = require("./is_result.js");
|
|
5
|
+
Object.defineProperty(exports, "isResult", { enumerable: true, get: function () { return is_result_js_1.isResult; } });
|
package/script/mod.d.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { err as _Err, ok, type Result, type Err, ResultAsync, okAsync as neverthrowOkAsync } from 'neverthrow';
|
|
2
|
+
/**
|
|
3
|
+
* Create an error object with literal type preservation
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const error = makeErr('not_found', 'User not found')
|
|
7
|
+
* // ✅ Type: { type: 'not_found', message: string }
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const error = makeErr('not_found', 'User not found', { userId: '123' })
|
|
11
|
+
* // ✅ Type: { type: 'not_found', message: string, userId: string }
|
|
12
|
+
*/
|
|
13
|
+
declare const makeErr: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => {
|
|
14
|
+
type: TType;
|
|
15
|
+
message: string;
|
|
16
|
+
} & TAdditional;
|
|
17
|
+
/**
|
|
18
|
+
* Create an async Err ResultAsync with automatic literal type preservation
|
|
19
|
+
*
|
|
20
|
+
* Async version of err() - same signature, returns ResultAsync instead of Result.
|
|
21
|
+
* Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // ✅ Simple error
|
|
25
|
+
* return errAsync('not_found', 'User not found')
|
|
26
|
+
* // Type: ResultAsync<never, { type: 'not_found', message: string }>
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // ✅ Error with additional properties
|
|
30
|
+
* return errAsync('not_found', 'User not found', { userId: '123' })
|
|
31
|
+
* // Type: ResultAsync<never, { type: 'not_found', message: string, userId: string }>
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // ✅ Error with complex additional data
|
|
35
|
+
* return errAsync('validation_failed', 'Invalid input', {
|
|
36
|
+
* field: 'email',
|
|
37
|
+
* errors: ['Invalid format']
|
|
38
|
+
* })
|
|
39
|
+
* // Type: ResultAsync<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
|
|
40
|
+
*/
|
|
41
|
+
declare const errAsync: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => ResultAsync<never, {
|
|
42
|
+
type: TType;
|
|
43
|
+
message: string;
|
|
44
|
+
} & TAdditional>;
|
|
45
|
+
/**
|
|
46
|
+
* Re-export okAsync from neverthrow for consistency
|
|
47
|
+
* Creates a successful ResultAsync
|
|
48
|
+
*/
|
|
49
|
+
declare const okAsync: typeof neverthrowOkAsync;
|
|
50
|
+
/**
|
|
51
|
+
* Utility type for defining error types concisely
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* // Instead of:
|
|
55
|
+
* type UserNotFoundError = {
|
|
56
|
+
* type: 'user_not_found'
|
|
57
|
+
* message: string
|
|
58
|
+
* userId: UserId
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* // Write:
|
|
62
|
+
* type UserNotFoundError = ErrorType<'user_not_found', { userId: UserId }>
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* // Error without additional properties:
|
|
66
|
+
* type InvalidOperationError = ErrorType<'invalid_operation'>
|
|
67
|
+
*/
|
|
68
|
+
type ErrorType<TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>> = {
|
|
69
|
+
type: TType;
|
|
70
|
+
message: string;
|
|
71
|
+
} & TAdditional;
|
|
72
|
+
/**
|
|
73
|
+
* Extract the error type from a Result or Promise<Result>
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // From async function
|
|
77
|
+
* const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
|
|
78
|
+
* type GetUserError = ExtractError<ReturnType<typeof getUser>>
|
|
79
|
+
* // Type: UserNotFoundError
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* // From Result type directly
|
|
83
|
+
* type MyResult = Result<User, InvalidError>
|
|
84
|
+
* type MyError = ExtractError<MyResult>
|
|
85
|
+
* // Type: InvalidError
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* // Works with composed errors
|
|
89
|
+
* const replaceVersion = async (): Promise<Result<Version, VersionNotFoundError | VersionExistsError>> => { ... }
|
|
90
|
+
* type ReplaceError = ExtractError<ReturnType<typeof replaceVersion>>
|
|
91
|
+
* // Type: VersionNotFoundError | VersionExistsError
|
|
92
|
+
*/
|
|
93
|
+
type ExtractError<TResultOrPromise> = TResultOrPromise extends Promise<Result<unknown, infer TError>> ? TError : TResultOrPromise extends Result<unknown, infer TError> ? TError : never;
|
|
94
|
+
/**
|
|
95
|
+
* Extract the error type from a function that returns Result or Promise<Result>
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* // Simple extraction
|
|
99
|
+
* const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
|
|
100
|
+
* type GetUserError = ExtractFnError<typeof getUser>
|
|
101
|
+
* // Type: UserNotFoundError
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* // Compose errors from multiple functions
|
|
105
|
+
* const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
|
|
106
|
+
* const getImage = async (id: string): Promise<Result<Image, ImageNotFoundError>> => { ... }
|
|
107
|
+
* type CombinedError = ExtractFnError<typeof getUser> | ExtractFnError<typeof getImage>
|
|
108
|
+
* // Type: UserNotFoundError | ImageNotFoundError
|
|
109
|
+
*/
|
|
110
|
+
type ExtractFnError<TFunction extends (...args: unknown[]) => unknown> = ExtractError<ReturnType<TFunction>>;
|
|
111
|
+
/**
|
|
112
|
+
* Extract and combine error types from multiple Result or Promise<Result> types
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* type UserResult = Result<User, UserNotFoundError>
|
|
116
|
+
* type ImageResult = Promise<Result<Image, ImageNotFoundError>>
|
|
117
|
+
* type ProductResult = Result<Product, ProductNotFoundError>
|
|
118
|
+
*
|
|
119
|
+
* type CombinedError = ExtractErrors<[UserResult, ImageResult, ProductResult]>
|
|
120
|
+
* // Type: UserNotFoundError | ImageNotFoundError | ProductNotFoundError
|
|
121
|
+
*/
|
|
122
|
+
type ExtractErrors<TResults extends readonly unknown[]> = TResults extends readonly [
|
|
123
|
+
infer TFirst,
|
|
124
|
+
...infer TRest
|
|
125
|
+
] ? ExtractError<TFirst> | ExtractErrors<TRest> : never;
|
|
126
|
+
/**
|
|
127
|
+
* Extract and combine error types from multiple functions that return Result or Promise<Result>
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
|
|
131
|
+
* const getImage = async (id: string): Promise<Result<Image, ImageNotFoundError>> => { ... }
|
|
132
|
+
* const deleteProduct = async (id: string): Promise<Result<void, ProductNotFoundError>> => { ... }
|
|
133
|
+
*
|
|
134
|
+
* type CombinedError = ExtractFnsError<[typeof getUser, typeof getImage, typeof deleteProduct]>
|
|
135
|
+
* // Type: UserNotFoundError | ImageNotFoundError | ProductNotFoundError
|
|
136
|
+
*/
|
|
137
|
+
type ExtractFnsError<TFunctions extends readonly ((...args: unknown[]) => unknown)[]> = TFunctions extends readonly [
|
|
138
|
+
infer TFirst,
|
|
139
|
+
...infer TRest extends readonly ((...args: unknown[]) => unknown)[]
|
|
140
|
+
] ? ExtractFnError<TFirst & ((...args: unknown[]) => unknown)> | ExtractFnsError<TRest> : never;
|
|
141
|
+
/**
|
|
142
|
+
* Raw error function from neverthrow - use for lifting database errors directly
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* const seedResult = await songSeeds.get.one.byId(songSeedId)
|
|
146
|
+
* if (seedResult.isErr()) {
|
|
147
|
+
* return rawErr(seedResult.error)
|
|
148
|
+
* }
|
|
149
|
+
*/
|
|
150
|
+
declare const rawErr: typeof _Err;
|
|
151
|
+
export { makeErr, errAsync, ok, okAsync, rawErr, _Err, ResultAsync };
|
|
152
|
+
export type { Result, Err, ErrorType, ExtractError, ExtractFnError, ExtractErrors, ExtractFnsError };
|
|
153
|
+
export { err } from './err/mod.js';
|
|
154
|
+
export { isResult } from './is_result/mod.js';
|
|
155
|
+
export { propagateErr } from './propagate_err/mod.js';
|
|
156
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"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"}
|
package/script/mod.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.propagateErr = exports.isResult = exports.err = exports.ResultAsync = exports._Err = exports.rawErr = exports.okAsync = exports.ok = exports.errAsync = exports.makeErr = void 0;
|
|
4
|
+
const neverthrow_1 = require("neverthrow");
|
|
5
|
+
Object.defineProperty(exports, "_Err", { enumerable: true, get: function () { return neverthrow_1.err; } });
|
|
6
|
+
Object.defineProperty(exports, "ok", { enumerable: true, get: function () { return neverthrow_1.ok; } });
|
|
7
|
+
Object.defineProperty(exports, "ResultAsync", { enumerable: true, get: function () { return neverthrow_1.ResultAsync; } });
|
|
8
|
+
/**
|
|
9
|
+
* Create an error object with literal type preservation
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const error = makeErr('not_found', 'User not found')
|
|
13
|
+
* // ✅ Type: { type: 'not_found', message: string }
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const error = makeErr('not_found', 'User not found', { userId: '123' })
|
|
17
|
+
* // ✅ Type: { type: 'not_found', message: string, userId: string }
|
|
18
|
+
*/
|
|
19
|
+
const makeErr = (type, message, additional) => ({
|
|
20
|
+
...additional,
|
|
21
|
+
type,
|
|
22
|
+
message,
|
|
23
|
+
});
|
|
24
|
+
exports.makeErr = makeErr;
|
|
25
|
+
/**
|
|
26
|
+
* Create an async Err ResultAsync with automatic literal type preservation
|
|
27
|
+
*
|
|
28
|
+
* Async version of err() - same signature, returns ResultAsync instead of Result.
|
|
29
|
+
* Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // ✅ Simple error
|
|
33
|
+
* return errAsync('not_found', 'User not found')
|
|
34
|
+
* // Type: ResultAsync<never, { type: 'not_found', message: string }>
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // ✅ Error with additional properties
|
|
38
|
+
* return errAsync('not_found', 'User not found', { userId: '123' })
|
|
39
|
+
* // Type: ResultAsync<never, { type: 'not_found', message: string, userId: string }>
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // ✅ Error with complex additional data
|
|
43
|
+
* return errAsync('validation_failed', 'Invalid input', {
|
|
44
|
+
* field: 'email',
|
|
45
|
+
* errors: ['Invalid format']
|
|
46
|
+
* })
|
|
47
|
+
* // Type: ResultAsync<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
|
|
48
|
+
*/
|
|
49
|
+
const errAsync = (type, message, additional) => (0, neverthrow_1.errAsync)({
|
|
50
|
+
...additional,
|
|
51
|
+
type,
|
|
52
|
+
message,
|
|
53
|
+
});
|
|
54
|
+
exports.errAsync = errAsync;
|
|
55
|
+
/**
|
|
56
|
+
* Re-export okAsync from neverthrow for consistency
|
|
57
|
+
* Creates a successful ResultAsync
|
|
58
|
+
*/
|
|
59
|
+
const okAsync = neverthrow_1.okAsync;
|
|
60
|
+
exports.okAsync = okAsync;
|
|
61
|
+
/**
|
|
62
|
+
* Raw error function from neverthrow - use for lifting database errors directly
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* const seedResult = await songSeeds.get.one.byId(songSeedId)
|
|
66
|
+
* if (seedResult.isErr()) {
|
|
67
|
+
* return rawErr(seedResult.error)
|
|
68
|
+
* }
|
|
69
|
+
*/
|
|
70
|
+
const rawErr = neverthrow_1.err;
|
|
71
|
+
exports.rawErr = rawErr;
|
|
72
|
+
var mod_js_1 = require("./err/mod.js");
|
|
73
|
+
Object.defineProperty(exports, "err", { enumerable: true, get: function () { return mod_js_1.err; } });
|
|
74
|
+
var mod_js_2 = require("./is_result/mod.js");
|
|
75
|
+
Object.defineProperty(exports, "isResult", { enumerable: true, get: function () { return mod_js_2.isResult; } });
|
|
76
|
+
var mod_js_3 = require("./propagate_err/mod.js");
|
|
77
|
+
Object.defineProperty(exports, "propagateErr", { enumerable: true, get: function () { return mod_js_3.propagateErr; } });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/propagate_err/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.propagateErr = void 0;
|
|
4
|
+
var propagate_err_js_1 = require("./propagate_err.js");
|
|
5
|
+
Object.defineProperty(exports, "propagateErr", { enumerable: true, get: function () { return propagate_err_js_1.propagateErr; } });
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Result } from 'neverthrow';
|
|
2
|
+
/**
|
|
3
|
+
* Propagates an error Result to a different success type context.
|
|
4
|
+
*
|
|
5
|
+
* This is safe because error Results never contain the success value - only the error.
|
|
6
|
+
* TypeScript's structural typing prevents direct assignment of Result<T, E> to Result<U, E>
|
|
7
|
+
* even though the error type is identical and we're in the error branch.
|
|
8
|
+
*
|
|
9
|
+
* Common use case: Early return from a function that creates multiple items. If creating
|
|
10
|
+
* item 2 fails with Result<Item, DatabaseError>, we need to return Result<Item[], DatabaseError>.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const result = await createUser(db, data) // Result<User, DatabaseError>
|
|
14
|
+
* if (result.isErr()) {
|
|
15
|
+
* // Need to return Result<Profile, DatabaseError> but have Result<User, DatabaseError>
|
|
16
|
+
* return propagateErr(result)
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // In bulk creation, propagate single-item error to array context
|
|
21
|
+
* const itemResult = await createItem(data) // Result<Item, Error>
|
|
22
|
+
* if (itemResult.isErr()) {
|
|
23
|
+
* return propagateErr<Item[], Error>(itemResult) // Result<Item[], Error>
|
|
24
|
+
* }
|
|
25
|
+
*/
|
|
26
|
+
declare const propagateErr: <TNew, E>(errorResult: Result<unknown, E>) => Result<TNew, E>;
|
|
27
|
+
export { propagateErr };
|
|
28
|
+
//# sourceMappingURL=propagate_err.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propagate_err.d.ts","sourceRoot":"","sources":["../../src/propagate_err/propagate_err.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,YAAY,GAAI,IAAI,EAAE,CAAC,EAAE,aAAa,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,KAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAI9E,CAAA;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.propagateErr = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Propagates an error Result to a different success type context.
|
|
6
|
+
*
|
|
7
|
+
* This is safe because error Results never contain the success value - only the error.
|
|
8
|
+
* TypeScript's structural typing prevents direct assignment of Result<T, E> to Result<U, E>
|
|
9
|
+
* even though the error type is identical and we're in the error branch.
|
|
10
|
+
*
|
|
11
|
+
* Common use case: Early return from a function that creates multiple items. If creating
|
|
12
|
+
* item 2 fails with Result<Item, DatabaseError>, we need to return Result<Item[], DatabaseError>.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const result = await createUser(db, data) // Result<User, DatabaseError>
|
|
16
|
+
* if (result.isErr()) {
|
|
17
|
+
* // Need to return Result<Profile, DatabaseError> but have Result<User, DatabaseError>
|
|
18
|
+
* return propagateErr(result)
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // In bulk creation, propagate single-item error to array context
|
|
23
|
+
* const itemResult = await createItem(data) // Result<Item, Error>
|
|
24
|
+
* if (itemResult.isErr()) {
|
|
25
|
+
* return propagateErr<Item[], Error>(itemResult) // Result<Item[], Error>
|
|
26
|
+
* }
|
|
27
|
+
*/
|
|
28
|
+
const propagateErr = (errorResult) => {
|
|
29
|
+
// Type assertion is safe: we're only propagating errors, and error Results
|
|
30
|
+
// don't contain the success value. The error type E is preserved exactly.
|
|
31
|
+
return errorResult;
|
|
32
|
+
};
|
|
33
|
+
exports.propagateErr = propagateErr;
|