errore 0.1.0 → 0.3.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/README.md ADDED
@@ -0,0 +1,307 @@
1
+ # errore
2
+
3
+ Type-safe errors as values for TypeScript. Like Go, but with full type inference.
4
+
5
+ ## Why?
6
+
7
+ Instead of wrapping values in a `Result<T, E>` type, functions simply return `E | T`. TypeScript's type narrowing handles the rest:
8
+
9
+ ```ts
10
+ // Go-style: errors as values
11
+ const user = await fetchUser(id)
12
+ if (isError(user)) return user // TypeScript narrows type
13
+ console.log(user.name) // user is now User, not Error | User
14
+ ```
15
+
16
+ ## Install
17
+
18
+ ```sh
19
+ npm install errore
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```ts
25
+ import { tryAsync, isError, TaggedError, matchError } from 'errore'
26
+
27
+ // Define typed errors
28
+ class NotFoundError extends TaggedError('NotFoundError')<{
29
+ id: string
30
+ message: string
31
+ }>() {
32
+ constructor(args: { id: string }) {
33
+ super({ ...args, message: `User ${args.id} not found` })
34
+ }
35
+ }
36
+
37
+ class DbError extends TaggedError('DbError')<{
38
+ message: string
39
+ cause: unknown
40
+ }>() {}
41
+
42
+ // Function returns Error | Value (no wrapper!)
43
+ async function getUser(id: string): Promise<NotFoundError | DbError | User> {
44
+ const result = await tryAsync({
45
+ try: () => db.query(id),
46
+ catch: e => new DbError({ message: 'Query failed', cause: e })
47
+ })
48
+
49
+ if (isError(result)) return result
50
+ if (!result) return new NotFoundError({ id })
51
+
52
+ return result
53
+ }
54
+
55
+ // Caller handles errors explicitly
56
+ const user = await getUser('123')
57
+
58
+ if (isError(user)) {
59
+ matchError(user, {
60
+ NotFoundError: e => console.log(`User ${e.id} not found`),
61
+ DbError: e => console.log(`Database error: ${e.message}`)
62
+ })
63
+ return
64
+ }
65
+
66
+ // TypeScript knows: user is User
67
+ console.log(user.name)
68
+ ```
69
+
70
+ ## API
71
+
72
+ ### Type Guards
73
+
74
+ ```ts
75
+ import { isError, isOk } from 'errore'
76
+
77
+ const result: NetworkError | User = await fetchUser(id)
78
+
79
+ if (isError(result)) {
80
+ // result is NetworkError
81
+ return result
82
+ }
83
+ // result is User
84
+ ```
85
+
86
+ ### Try Functions
87
+
88
+ ```ts
89
+ import { tryFn, tryAsync } from 'errore'
90
+
91
+ // Sync - wraps exceptions in UnhandledError
92
+ const parsed = tryFn(() => JSON.parse(input))
93
+
94
+ // Sync - with custom error type
95
+ const parsed = tryFn({
96
+ try: () => JSON.parse(input),
97
+ catch: e => new ParseError({ cause: e })
98
+ })
99
+
100
+ // Async
101
+ const response = await tryAsync(() => fetch(url))
102
+
103
+ // Async - with custom error
104
+ const response = await tryAsync({
105
+ try: () => fetch(url),
106
+ catch: e => new NetworkError({ cause: e })
107
+ })
108
+ ```
109
+
110
+ ### Transformations
111
+
112
+ ```ts
113
+ import { map, mapError, andThen, tap } from 'errore'
114
+
115
+ // Transform value (if not error)
116
+ const name = map(user, u => u.name)
117
+
118
+ // Transform error
119
+ const appError = mapError(dbError, e => new AppError({ cause: e }))
120
+
121
+ // Chain operations
122
+ const posts = andThen(user, u => fetchPosts(u.id))
123
+
124
+ // Side effects
125
+ const logged = tap(user, u => console.log('Got user:', u.name))
126
+ ```
127
+
128
+ ### Extraction
129
+
130
+ ```ts
131
+ import { unwrap, unwrapOr, match, partition } from 'errore'
132
+
133
+ // Extract or throw
134
+ const user = unwrap(result)
135
+ const user = unwrap(result, 'Custom error message')
136
+
137
+ // Extract or fallback
138
+ const name = unwrapOr(result, 'Anonymous')
139
+
140
+ // Pattern match
141
+ const message = match(result, {
142
+ ok: user => `Hello, ${user.name}`,
143
+ err: error => `Failed: ${error.message}`
144
+ })
145
+
146
+ // Split array into [successes, errors]
147
+ const [users, errors] = partition(results)
148
+ ```
149
+
150
+ ### Tagged Errors
151
+
152
+ ```ts
153
+ import { TaggedError, matchError, matchErrorPartial } from 'errore'
154
+
155
+ // Define errors with _tag discriminant
156
+ class ValidationError extends TaggedError('ValidationError')<{
157
+ field: string
158
+ message: string
159
+ }>() {}
160
+
161
+ class NetworkError extends TaggedError('NetworkError')<{
162
+ url: string
163
+ message: string
164
+ }>() {}
165
+
166
+ type AppError = ValidationError | NetworkError
167
+
168
+ // Exhaustive matching (TypeScript ensures all cases handled)
169
+ matchError(error, {
170
+ ValidationError: e => `Invalid ${e.field}`,
171
+ NetworkError: e => `Failed to fetch ${e.url}`
172
+ })
173
+
174
+ // Partial matching with fallback
175
+ matchErrorPartial(error, {
176
+ ValidationError: e => `Invalid ${e.field}`
177
+ }, e => `Unknown error: ${e.message}`)
178
+
179
+ // Type guards
180
+ ValidationError.is(value) // specific class
181
+ TaggedError.is(value) // any tagged error
182
+ ```
183
+
184
+ ## How Type Safety Works
185
+
186
+ TypeScript narrows types after `instanceof Error` checks:
187
+
188
+ ```ts
189
+ function example(result: NetworkError | User): string {
190
+ if (result instanceof Error) {
191
+ // TypeScript knows: result is NetworkError
192
+ return result.message
193
+ }
194
+ // TypeScript knows: result is User (Error excluded)
195
+ return result.name
196
+ }
197
+ ```
198
+
199
+ This works because:
200
+ 1. `Error` is a built-in class TypeScript understands
201
+ 2. Custom error classes extend `Error`
202
+ 3. After an `instanceof Error` check, TS excludes all Error subtypes
203
+
204
+ ## Result + Option Combined: `Error | T | null`
205
+
206
+ One of errore's best features: you can naturally combine error handling with optional values. No wrapper nesting needed!
207
+
208
+ In Rust, you'd need `Result<Option<T>, E>` or `Option<Result<T, E>>` and worry about the order. Here it's just a union:
209
+
210
+ ```ts
211
+ // Result + Option in one natural type
212
+ function findUser(id: string): NotFoundError | User | null {
213
+ if (id === 'bad') return new NotFoundError({ id })
214
+ if (id === 'missing') return null
215
+ return { id, name: 'Alice' }
216
+ }
217
+
218
+ const user = findUser('123')
219
+
220
+ // Handle error first
221
+ if (isError(user)) {
222
+ return user.message // TypeScript: user is NotFoundError
223
+ }
224
+
225
+ // Handle null/missing case - use ?. and ?? naturally!
226
+ const name = user?.name ?? 'Anonymous'
227
+
228
+ // Or check explicitly
229
+ if (user === null) {
230
+ return 'User not found'
231
+ }
232
+
233
+ // TypeScript knows: user is User
234
+ console.log(user.name)
235
+ ```
236
+
237
+ ### Works with `undefined` too
238
+
239
+ ```ts
240
+ function lookup(key: string): NetworkError | string | undefined {
241
+ if (key === 'fail') return new NetworkError({ url: '/api', message: 'Failed' })
242
+ if (key === 'missing') return undefined
243
+ return 'found-value'
244
+ }
245
+
246
+ const value = lookup('key')
247
+
248
+ if (isError(value)) return value
249
+
250
+ // ?? works naturally with undefined
251
+ const result = value ?? 'default'
252
+ ```
253
+
254
+ ### Triple union: `Error | T | null | undefined`
255
+
256
+ Even this works with full type inference:
257
+
258
+ ```ts
259
+ function query(sql: string): ValidationError | { rows: string[] } | null | undefined {
260
+ if (sql === 'invalid') return new ValidationError({ field: 'sql', message: 'Bad' })
261
+ if (sql === 'empty') return null // explicitly no data
262
+ if (sql === 'no-table') return undefined // table doesn't exist
263
+ return { rows: ['a', 'b'] }
264
+ }
265
+
266
+ const result = query('SELECT *')
267
+
268
+ if (isError(result)) {
269
+ return result.field // TypeScript: ValidationError
270
+ }
271
+
272
+ if (result == null) {
273
+ return 'no data' // handles both null and undefined
274
+ }
275
+
276
+ // TypeScript: { rows: string[] }
277
+ console.log(result.rows)
278
+ ```
279
+
280
+ ### Why this is better than Rust/Zig
281
+
282
+ | Language | Result + Option | Order matters? |
283
+ |----------|-----------------|----------------|
284
+ | Rust | `Result<Option<T>, E>` or `Option<Result<T, E>>` | Yes, must unwrap in order |
285
+ | Zig | `!?T` (error union + optional) | Yes, specific syntax |
286
+ | **errore** | `Error \| T \| null` | **No!** Check in any order |
287
+
288
+ With errore:
289
+ - Use `?.` and `??` naturally
290
+ - Check `isError()` or `=== null` in any order
291
+ - No unwrapping ceremony
292
+ - TypeScript infers everything
293
+
294
+ ## Comparison with Result Types
295
+
296
+ | Result Pattern | errore |
297
+ |---------------|--------|
298
+ | `Result.ok(value)` | just `return value` |
299
+ | `Result.err(error)` | just `return error` |
300
+ | `result.value` | direct access after guard |
301
+ | `result.map(fn)` | `map(result, fn)` |
302
+ | `Result<User, Error>` | `Error \| User` |
303
+ | `Result<Option<T>, E>` | `Error \| T \| null` |
304
+
305
+ ## License
306
+
307
+ MIT
package/dist/index.d.mts CHANGED
@@ -112,7 +112,7 @@ declare class UnhandledError extends UnhandledError_base {
112
112
 
113
113
  /**
114
114
  * Type guard: checks if value is an Error.
115
- * After this check, TypeScript narrows the type.
115
+ * After this check, TypeScript narrows the type to the error types in the union.
116
116
  *
117
117
  * @example
118
118
  * const result = await fetchUser(id)
@@ -123,7 +123,7 @@ declare class UnhandledError extends UnhandledError_base {
123
123
  * // result is narrowed to User
124
124
  * console.log(result.name)
125
125
  */
126
- declare function isError<T, E extends Error>(value: E | T): value is E;
126
+ declare function isError<V>(value: V): value is Extract<V, Error>;
127
127
  /**
128
128
  * Type guard: checks if value is NOT an Error.
129
129
  * Inverse of isError for convenience.
@@ -134,7 +134,7 @@ declare function isError<T, E extends Error>(value: E | T): value is E;
134
134
  * console.log(result.name) // result is User
135
135
  * }
136
136
  */
137
- declare function isOk<T, E extends Error>(value: E | T): value is T;
137
+ declare function isOk<V>(value: V): value is Exclude<V, Error>;
138
138
  /**
139
139
  * Execute a sync function and return either the value or an error.
140
140
  *
@@ -187,7 +187,7 @@ declare function tryAsync<T, E extends Error>(opts: {
187
187
  * // If user is User, result is string
188
188
  * // If user is NotFoundError, result is NotFoundError
189
189
  */
190
- declare function map<T, U, E extends Error>(value: E | T, fn: (v: T) => U): E | U;
190
+ declare function map<V, U>(value: V, fn: (v: Exclude<V, Error>) => U): Extract<V, Error> | U;
191
191
  /**
192
192
  * Transform the error if it is an error.
193
193
  * If the value is not an error, returns it unchanged.
@@ -196,7 +196,7 @@ declare function map<T, U, E extends Error>(value: E | T, fn: (v: T) => U): E |
196
196
  * const result = mapError(fetchResult, e => new AppError({ cause: e }))
197
197
  * // Converts any error type to AppError
198
198
  */
199
- declare function mapError<T, E extends Error, E2 extends Error>(value: E | T, fn: (e: E) => E2): E2 | T;
199
+ declare function mapError<V, E2 extends Error>(value: V, fn: (e: Extract<V, Error>) => E2): E2 | Exclude<V, Error>;
200
200
  /**
201
201
  * Chain another errore-returning function.
202
202
  * If the value is an error, returns it unchanged.
@@ -207,7 +207,7 @@ declare function mapError<T, E extends Error, E2 extends Error>(value: E | T, fn
207
207
  * // If userId is ValidationError, result is ValidationError
208
208
  * // If userId is string, result is whatever fetchUser returns
209
209
  */
210
- declare function andThen<T, U, E extends Error, E2 extends Error>(value: E | T, fn: (v: T) => E2 | U): E | E2 | U;
210
+ declare function andThen<V, R>(value: V, fn: (v: Exclude<V, Error>) => R): Extract<V, Error> | R;
211
211
  /**
212
212
  * Async version of andThen.
213
213
  *
@@ -217,7 +217,7 @@ declare function andThen<T, U, E extends Error, E2 extends Error>(value: E | T,
217
217
  * return user
218
218
  * })
219
219
  */
220
- declare function andThenAsync<T, U, E extends Error, E2 extends Error>(value: E | T, fn: (v: T) => Promise<E2 | U>): Promise<E | E2 | U>;
220
+ declare function andThenAsync<V, R>(value: V, fn: (v: Exclude<V, Error>) => Promise<R>): Promise<Extract<V, Error> | R>;
221
221
  /**
222
222
  * Run a side effect if the value is not an error.
223
223
  * Returns the original value unchanged.
@@ -225,7 +225,7 @@ declare function andThenAsync<T, U, E extends Error, E2 extends Error>(value: E
225
225
  * @example
226
226
  * const result = tap(user, u => console.log('Got user:', u.name))
227
227
  */
228
- declare function tap<T, E extends Error>(value: E | T, fn: (v: T) => void): E | T;
228
+ declare function tap<V>(value: V, fn: (v: Exclude<V, Error>) => void): V;
229
229
  /**
230
230
  * Async version of tap.
231
231
  *
@@ -234,7 +234,7 @@ declare function tap<T, E extends Error>(value: E | T, fn: (v: T) => void): E |
234
234
  * await logToService(u)
235
235
  * })
236
236
  */
237
- declare function tapAsync<T, E extends Error>(value: E | T, fn: (v: T) => Promise<void>): Promise<E | T>;
237
+ declare function tapAsync<V>(value: V, fn: (v: Exclude<V, Error>) => Promise<void>): Promise<V>;
238
238
 
239
239
  /**
240
240
  * Extract the value or throw if it's an error.
@@ -246,7 +246,7 @@ declare function tapAsync<T, E extends Error>(value: E | T, fn: (v: T) => Promis
246
246
  * @example With custom message
247
247
  * const user = unwrap(result, 'Failed to get user')
248
248
  */
249
- declare function unwrap<T, E extends Error>(value: E | T, message?: string): T;
249
+ declare function unwrap<V>(value: V, message?: string): Exclude<V, Error>;
250
250
  /**
251
251
  * Extract the value or return a fallback if it's an error.
252
252
  *
@@ -255,7 +255,7 @@ declare function unwrap<T, E extends Error>(value: E | T, message?: string): T;
255
255
  * // If result is User, returns user
256
256
  * // If result is Error, returns 'Anonymous'
257
257
  */
258
- declare function unwrapOr<T, U, E extends Error>(value: E | T, fallback: U): T | U;
258
+ declare function unwrapOr<V, U>(value: V, fallback: U): Exclude<V, Error> | U;
259
259
  /**
260
260
  * Pattern match on an errore value.
261
261
  * Handles both success and error cases.
@@ -266,9 +266,9 @@ declare function unwrapOr<T, U, E extends Error>(value: E | T, fallback: U): T |
266
266
  * err: error => `Failed: ${error.message}`
267
267
  * })
268
268
  */
269
- declare function match<T, E extends Error, R>(value: E | T, handlers: {
270
- ok: (v: T) => R;
271
- err: (e: E) => R;
269
+ declare function match<V, R>(value: V, handlers: {
270
+ ok: (v: Exclude<V, Error>) => R;
271
+ err: (e: Extract<V, Error>) => R;
272
272
  }): R;
273
273
  /**
274
274
  * Partition an array of errore values into [successes, errors].
@@ -277,7 +277,7 @@ declare function match<T, E extends Error, R>(value: E | T, handlers: {
277
277
  * const results = await Promise.all(ids.map(fetchUser))
278
278
  * const [users, errors] = partition(results)
279
279
  */
280
- declare function partition<T, E extends Error>(values: (E | T)[]): [T[], E[]];
280
+ declare function partition<V>(values: V[]): [Exclude<V, Error>[], Extract<V, Error>[]];
281
281
  /**
282
282
  * Flatten a nested errore: (E1 | (E2 | T)) becomes (E1 | E2 | T).
283
283
  * Useful when chaining operations that can fail.
@@ -286,6 +286,6 @@ declare function partition<T, E extends Error>(values: (E | T)[]): [T[], E[]];
286
286
  * const nested: NetworkError | (ParseError | User) = await fetchAndParse()
287
287
  * const flat: NetworkError | ParseError | User = flatten(nested)
288
288
  */
289
- declare function flatten<T, E1 extends Error, E2 extends Error>(value: E1 | (E2 | T)): E1 | E2 | T;
289
+ declare function flatten<V>(value: V): V;
290
290
 
291
291
  export { type EnsureNotError, type Errore, type InferError, type InferValue, TaggedError, type TaggedErrorClass, type TaggedErrorInstance, UnhandledError, andThen, andThenAsync, flatten, isError, isOk, isTaggedError, map, mapError, match, matchError, matchErrorPartial, partition, tap, tapAsync, tryAsync, tryFn, unwrap, unwrapOr };
package/dist/index.d.ts CHANGED
@@ -112,7 +112,7 @@ declare class UnhandledError extends UnhandledError_base {
112
112
 
113
113
  /**
114
114
  * Type guard: checks if value is an Error.
115
- * After this check, TypeScript narrows the type.
115
+ * After this check, TypeScript narrows the type to the error types in the union.
116
116
  *
117
117
  * @example
118
118
  * const result = await fetchUser(id)
@@ -123,7 +123,7 @@ declare class UnhandledError extends UnhandledError_base {
123
123
  * // result is narrowed to User
124
124
  * console.log(result.name)
125
125
  */
126
- declare function isError<T, E extends Error>(value: E | T): value is E;
126
+ declare function isError<V>(value: V): value is Extract<V, Error>;
127
127
  /**
128
128
  * Type guard: checks if value is NOT an Error.
129
129
  * Inverse of isError for convenience.
@@ -134,7 +134,7 @@ declare function isError<T, E extends Error>(value: E | T): value is E;
134
134
  * console.log(result.name) // result is User
135
135
  * }
136
136
  */
137
- declare function isOk<T, E extends Error>(value: E | T): value is T;
137
+ declare function isOk<V>(value: V): value is Exclude<V, Error>;
138
138
  /**
139
139
  * Execute a sync function and return either the value or an error.
140
140
  *
@@ -187,7 +187,7 @@ declare function tryAsync<T, E extends Error>(opts: {
187
187
  * // If user is User, result is string
188
188
  * // If user is NotFoundError, result is NotFoundError
189
189
  */
190
- declare function map<T, U, E extends Error>(value: E | T, fn: (v: T) => U): E | U;
190
+ declare function map<V, U>(value: V, fn: (v: Exclude<V, Error>) => U): Extract<V, Error> | U;
191
191
  /**
192
192
  * Transform the error if it is an error.
193
193
  * If the value is not an error, returns it unchanged.
@@ -196,7 +196,7 @@ declare function map<T, U, E extends Error>(value: E | T, fn: (v: T) => U): E |
196
196
  * const result = mapError(fetchResult, e => new AppError({ cause: e }))
197
197
  * // Converts any error type to AppError
198
198
  */
199
- declare function mapError<T, E extends Error, E2 extends Error>(value: E | T, fn: (e: E) => E2): E2 | T;
199
+ declare function mapError<V, E2 extends Error>(value: V, fn: (e: Extract<V, Error>) => E2): E2 | Exclude<V, Error>;
200
200
  /**
201
201
  * Chain another errore-returning function.
202
202
  * If the value is an error, returns it unchanged.
@@ -207,7 +207,7 @@ declare function mapError<T, E extends Error, E2 extends Error>(value: E | T, fn
207
207
  * // If userId is ValidationError, result is ValidationError
208
208
  * // If userId is string, result is whatever fetchUser returns
209
209
  */
210
- declare function andThen<T, U, E extends Error, E2 extends Error>(value: E | T, fn: (v: T) => E2 | U): E | E2 | U;
210
+ declare function andThen<V, R>(value: V, fn: (v: Exclude<V, Error>) => R): Extract<V, Error> | R;
211
211
  /**
212
212
  * Async version of andThen.
213
213
  *
@@ -217,7 +217,7 @@ declare function andThen<T, U, E extends Error, E2 extends Error>(value: E | T,
217
217
  * return user
218
218
  * })
219
219
  */
220
- declare function andThenAsync<T, U, E extends Error, E2 extends Error>(value: E | T, fn: (v: T) => Promise<E2 | U>): Promise<E | E2 | U>;
220
+ declare function andThenAsync<V, R>(value: V, fn: (v: Exclude<V, Error>) => Promise<R>): Promise<Extract<V, Error> | R>;
221
221
  /**
222
222
  * Run a side effect if the value is not an error.
223
223
  * Returns the original value unchanged.
@@ -225,7 +225,7 @@ declare function andThenAsync<T, U, E extends Error, E2 extends Error>(value: E
225
225
  * @example
226
226
  * const result = tap(user, u => console.log('Got user:', u.name))
227
227
  */
228
- declare function tap<T, E extends Error>(value: E | T, fn: (v: T) => void): E | T;
228
+ declare function tap<V>(value: V, fn: (v: Exclude<V, Error>) => void): V;
229
229
  /**
230
230
  * Async version of tap.
231
231
  *
@@ -234,7 +234,7 @@ declare function tap<T, E extends Error>(value: E | T, fn: (v: T) => void): E |
234
234
  * await logToService(u)
235
235
  * })
236
236
  */
237
- declare function tapAsync<T, E extends Error>(value: E | T, fn: (v: T) => Promise<void>): Promise<E | T>;
237
+ declare function tapAsync<V>(value: V, fn: (v: Exclude<V, Error>) => Promise<void>): Promise<V>;
238
238
 
239
239
  /**
240
240
  * Extract the value or throw if it's an error.
@@ -246,7 +246,7 @@ declare function tapAsync<T, E extends Error>(value: E | T, fn: (v: T) => Promis
246
246
  * @example With custom message
247
247
  * const user = unwrap(result, 'Failed to get user')
248
248
  */
249
- declare function unwrap<T, E extends Error>(value: E | T, message?: string): T;
249
+ declare function unwrap<V>(value: V, message?: string): Exclude<V, Error>;
250
250
  /**
251
251
  * Extract the value or return a fallback if it's an error.
252
252
  *
@@ -255,7 +255,7 @@ declare function unwrap<T, E extends Error>(value: E | T, message?: string): T;
255
255
  * // If result is User, returns user
256
256
  * // If result is Error, returns 'Anonymous'
257
257
  */
258
- declare function unwrapOr<T, U, E extends Error>(value: E | T, fallback: U): T | U;
258
+ declare function unwrapOr<V, U>(value: V, fallback: U): Exclude<V, Error> | U;
259
259
  /**
260
260
  * Pattern match on an errore value.
261
261
  * Handles both success and error cases.
@@ -266,9 +266,9 @@ declare function unwrapOr<T, U, E extends Error>(value: E | T, fallback: U): T |
266
266
  * err: error => `Failed: ${error.message}`
267
267
  * })
268
268
  */
269
- declare function match<T, E extends Error, R>(value: E | T, handlers: {
270
- ok: (v: T) => R;
271
- err: (e: E) => R;
269
+ declare function match<V, R>(value: V, handlers: {
270
+ ok: (v: Exclude<V, Error>) => R;
271
+ err: (e: Extract<V, Error>) => R;
272
272
  }): R;
273
273
  /**
274
274
  * Partition an array of errore values into [successes, errors].
@@ -277,7 +277,7 @@ declare function match<T, E extends Error, R>(value: E | T, handlers: {
277
277
  * const results = await Promise.all(ids.map(fetchUser))
278
278
  * const [users, errors] = partition(results)
279
279
  */
280
- declare function partition<T, E extends Error>(values: (E | T)[]): [T[], E[]];
280
+ declare function partition<V>(values: V[]): [Exclude<V, Error>[], Extract<V, Error>[]];
281
281
  /**
282
282
  * Flatten a nested errore: (E1 | (E2 | T)) becomes (E1 | E2 | T).
283
283
  * Useful when chaining operations that can fail.
@@ -286,6 +286,6 @@ declare function partition<T, E extends Error>(values: (E | T)[]): [T[], E[]];
286
286
  * const nested: NetworkError | (ParseError | User) = await fetchAndParse()
287
287
  * const flat: NetworkError | ParseError | User = flatten(nested)
288
288
  */
289
- declare function flatten<T, E1 extends Error, E2 extends Error>(value: E1 | (E2 | T)): E1 | E2 | T;
289
+ declare function flatten<V>(value: V): V;
290
290
 
291
291
  export { type EnsureNotError, type Errore, type InferError, type InferValue, TaggedError, type TaggedErrorClass, type TaggedErrorInstance, UnhandledError, andThen, andThenAsync, flatten, isError, isOk, isTaggedError, map, mapError, match, matchError, matchErrorPartial, partition, tap, tapAsync, tryAsync, tryFn, unwrap, unwrapOr };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "errore",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Type-safe errors as values for TypeScript. Like Go, but with full type inference.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -17,7 +17,8 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "build": "tsup src/index.ts --format cjs,esm --dts",
20
- "typecheck": "tsc --noEmit"
20
+ "typecheck": "tsc --noEmit",
21
+ "test": "vitest"
21
22
  },
22
23
  "keywords": [
23
24
  "error",
@@ -31,6 +32,7 @@
31
32
  "license": "MIT",
32
33
  "devDependencies": {
33
34
  "tsup": "^8.0.0",
34
- "typescript": "^5.0.0"
35
+ "typescript": "^5.0.0",
36
+ "vitest": "^3.2.4"
35
37
  }
36
38
  }