errore 0.9.0 → 0.10.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 +363 -13
- package/dist/error.d.ts +18 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +31 -0
- package/dist/factory.d.ts +2 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +4 -18
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +1006 -0
- package/package.json +5 -2
- package/src/error.ts +41 -6
- package/src/factory.ts +8 -0
- package/src/index.test.ts +236 -0
- package/src/index.ts +1 -1
package/README.md
CHANGED
|
@@ -4,13 +4,20 @@ Type-safe errors as values for TypeScript. Like Go, but with full type inference
|
|
|
4
4
|
|
|
5
5
|
## Why?
|
|
6
6
|
|
|
7
|
-
Instead of wrapping values in a `Result<T, E>` type, functions simply return `E | T`. TypeScript's type narrowing handles the rest:
|
|
7
|
+
Instead of wrapping values in a `Result<T, E>` type, functions simply return `E | T`. TypeScript's **type narrowing** handles the rest:
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
10
|
// Go-style: errors as values
|
|
11
|
-
const user = await
|
|
12
|
-
if (user instanceof
|
|
13
|
-
console.
|
|
11
|
+
const user = await getUser(id)
|
|
12
|
+
if (user instanceof NotFoundError) {
|
|
13
|
+
console.error('Missing:', user.id)
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
if (user instanceof DbError) {
|
|
17
|
+
console.error('DB failed:', user.reason)
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
console.log(user.username) // user is User, fully narrowed
|
|
14
21
|
```
|
|
15
22
|
|
|
16
23
|
## Install
|
|
@@ -21,6 +28,8 @@ npm install errore
|
|
|
21
28
|
|
|
22
29
|
## Quick Start
|
|
23
30
|
|
|
31
|
+
Define typed errors with **variable interpolation** and return **Error or Value** directly:
|
|
32
|
+
|
|
24
33
|
```ts
|
|
25
34
|
import * as errore from 'errore'
|
|
26
35
|
|
|
@@ -67,7 +76,7 @@ console.log(user.name)
|
|
|
67
76
|
|
|
68
77
|
## Example: API Error Handling
|
|
69
78
|
|
|
70
|
-
A complete example with custom base class
|
|
79
|
+
A complete example with **custom base class** and HTTP status codes:
|
|
71
80
|
|
|
72
81
|
```ts
|
|
73
82
|
import * as errore from 'errore'
|
|
@@ -139,7 +148,7 @@ app.post('/users/:id', async (req, res) => {
|
|
|
139
148
|
|
|
140
149
|
### createTaggedError
|
|
141
150
|
|
|
142
|
-
Create typed errors with
|
|
151
|
+
Create typed errors with **variable interpolation** in the message:
|
|
143
152
|
|
|
144
153
|
```ts
|
|
145
154
|
import * as errore from 'errore'
|
|
@@ -186,8 +195,136 @@ err.statusCode // 500 (inherited from AppError)
|
|
|
186
195
|
err instanceof AppError // true
|
|
187
196
|
```
|
|
188
197
|
|
|
198
|
+
### Error Wrapping and Context
|
|
199
|
+
|
|
200
|
+
Wrap errors with additional context while **preserving the original error** via `cause`:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
// Wrap with context, preserve original in cause
|
|
204
|
+
async function processUser(id: string): Promise<ServiceError | ProcessedUser> {
|
|
205
|
+
const user = await getUser(id) // returns NotFoundError | User
|
|
206
|
+
|
|
207
|
+
if (user instanceof Error) {
|
|
208
|
+
return new ServiceError({ id, cause: user })
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return process(user)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Access original error via cause
|
|
215
|
+
const result = await processUser('123')
|
|
216
|
+
if (result instanceof Error) {
|
|
217
|
+
console.log(result.message) // "Failed to process user 123"
|
|
218
|
+
|
|
219
|
+
if (result.cause instanceof NotFoundError) {
|
|
220
|
+
console.log(result.cause.id) // access original error's properties
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The error definitions:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
class NotFoundError extends errore.createTaggedError({
|
|
229
|
+
name: 'NotFoundError',
|
|
230
|
+
message: 'User $id not found'
|
|
231
|
+
}) {}
|
|
232
|
+
|
|
233
|
+
class ServiceError extends errore.createTaggedError({
|
|
234
|
+
name: 'ServiceError',
|
|
235
|
+
message: 'Failed to process user $id'
|
|
236
|
+
}) {}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Browser console** prints the full cause chain:
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
ServiceError: Failed to process user 123
|
|
243
|
+
at processUser (app.js:12)
|
|
244
|
+
at main (app.js:20)
|
|
245
|
+
Caused by: NotFoundError: User 123 not found
|
|
246
|
+
at getUser (app.js:5)
|
|
247
|
+
at processUser (app.js:8)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### findCause
|
|
251
|
+
|
|
252
|
+
Walk the `.cause` chain to find an ancestor matching a specific error class. Similar to Go's `errors.As` — checks the error itself first, then traverses `.cause` recursively:
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
import * as errore from 'errore'
|
|
256
|
+
|
|
257
|
+
class NotFoundError extends errore.createTaggedError({
|
|
258
|
+
name: 'NotFoundError',
|
|
259
|
+
message: 'User $id not found'
|
|
260
|
+
}) {}
|
|
261
|
+
|
|
262
|
+
class ServiceError extends errore.createTaggedError({
|
|
263
|
+
name: 'ServiceError',
|
|
264
|
+
message: 'Failed to process user $id'
|
|
265
|
+
}) {}
|
|
266
|
+
|
|
267
|
+
// Deep chain: ServiceError -> NotFoundError
|
|
268
|
+
const notFound = new NotFoundError({ id: '123' })
|
|
269
|
+
const service = new ServiceError({ id: '123', cause: notFound })
|
|
270
|
+
|
|
271
|
+
// Instance method on tagged errors
|
|
272
|
+
const found = service.findCause(NotFoundError)
|
|
273
|
+
found?.id // '123' — type-safe access
|
|
274
|
+
|
|
275
|
+
// Standalone function for any Error
|
|
276
|
+
const found2 = errore.findCause(service, NotFoundError)
|
|
277
|
+
found2?.id // '123'
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
This solves the problem where `result.cause instanceof MyError` only checks one level deep. `findCause` walks the entire chain:
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
// A -> B -> C chain
|
|
284
|
+
const c = new DbError({ message: 'connection reset' })
|
|
285
|
+
const b = new ServiceError({ id: '123', cause: c })
|
|
286
|
+
const a = new ApiError({ message: 'request failed', cause: b })
|
|
287
|
+
|
|
288
|
+
// Manual check only finds B
|
|
289
|
+
a.cause instanceof DbError // false — only checks one level
|
|
290
|
+
|
|
291
|
+
// findCause walks the full chain
|
|
292
|
+
a.findCause(DbError) // finds C ✓
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Returns `undefined` if no matching ancestor is found. Safe against circular `.cause` references.
|
|
296
|
+
|
|
297
|
+
### Custom Base Class with `extends`
|
|
298
|
+
|
|
299
|
+
Use `extends` to inherit from a custom base class. The error will pass `instanceof` for both the base class and the specific error class:
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
class AppError extends Error {
|
|
303
|
+
statusCode = 500
|
|
304
|
+
toResponse() { return { error: this.message, code: this.statusCode } }
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
class NotFoundError extends errore.createTaggedError({
|
|
308
|
+
name: 'NotFoundError',
|
|
309
|
+
message: 'Resource $id not found',
|
|
310
|
+
extends: AppError
|
|
311
|
+
}) {
|
|
312
|
+
statusCode = 404
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const err = new NotFoundError({ id: '123' })
|
|
316
|
+
err instanceof NotFoundError // true
|
|
317
|
+
err instanceof AppError // true
|
|
318
|
+
err instanceof Error // true
|
|
319
|
+
|
|
320
|
+
err.statusCode // 404
|
|
321
|
+
err.toResponse() // { error: 'Resource 123 not found', code: 404 }
|
|
322
|
+
```
|
|
323
|
+
|
|
189
324
|
### Type Guards
|
|
190
325
|
|
|
326
|
+
Use **instanceof checks** to narrow union types:
|
|
327
|
+
|
|
191
328
|
```ts
|
|
192
329
|
const result: NetworkError | User = await fetchUser(id)
|
|
193
330
|
|
|
@@ -200,14 +337,16 @@ if (result instanceof Error) {
|
|
|
200
337
|
|
|
201
338
|
### Try Functions
|
|
202
339
|
|
|
340
|
+
**Wrap exceptions** as error values:
|
|
341
|
+
|
|
203
342
|
```ts
|
|
204
343
|
import * as errore from 'errore'
|
|
205
344
|
|
|
206
345
|
// Sync - wraps exceptions in UnhandledError
|
|
207
|
-
const parsed = errore.
|
|
346
|
+
const parsed = errore.try(() => JSON.parse(input))
|
|
208
347
|
|
|
209
348
|
// Sync - with custom error type
|
|
210
|
-
const parsed = errore.
|
|
349
|
+
const parsed = errore.try({
|
|
211
350
|
try: () => JSON.parse(input),
|
|
212
351
|
catch: e => new ParseError({ reason: e.message, cause: e })
|
|
213
352
|
})
|
|
@@ -224,6 +363,8 @@ const response = await errore.tryAsync({
|
|
|
224
363
|
|
|
225
364
|
### Transformations
|
|
226
365
|
|
|
366
|
+
**Transform and chain** operations:
|
|
367
|
+
|
|
227
368
|
```ts
|
|
228
369
|
import * as errore from 'errore'
|
|
229
370
|
|
|
@@ -242,6 +383,8 @@ const logged = errore.tap(user, u => console.log('Got user:', u.name))
|
|
|
242
383
|
|
|
243
384
|
### Extraction
|
|
244
385
|
|
|
386
|
+
**Extract values** or throw, **split arrays** by success/error:
|
|
387
|
+
|
|
245
388
|
```ts
|
|
246
389
|
import * as errore from 'errore'
|
|
247
390
|
|
|
@@ -264,7 +407,7 @@ const [users, errors] = errore.partition(results)
|
|
|
264
407
|
|
|
265
408
|
### Error Matching
|
|
266
409
|
|
|
267
|
-
|
|
410
|
+
**Exhaustive pattern matching** with `matchError`. Always assign results to a variable and keep callbacks pure:
|
|
268
411
|
|
|
269
412
|
```ts
|
|
270
413
|
import * as errore from 'errore'
|
|
@@ -298,7 +441,7 @@ ValidationError.is(value) // specific class
|
|
|
298
441
|
|
|
299
442
|
## How Type Safety Works
|
|
300
443
|
|
|
301
|
-
TypeScript narrows types after `instanceof Error` checks:
|
|
444
|
+
TypeScript **narrows types** after `instanceof Error` checks:
|
|
302
445
|
|
|
303
446
|
```ts
|
|
304
447
|
function example(result: NetworkError | User): string {
|
|
@@ -318,7 +461,7 @@ This works because:
|
|
|
318
461
|
|
|
319
462
|
## Result + Option Combined: `Error | T | null`
|
|
320
463
|
|
|
321
|
-
|
|
464
|
+
Naturally combine **error handling with optional values**. No wrapper nesting needed!
|
|
322
465
|
|
|
323
466
|
```ts
|
|
324
467
|
import * as errore from 'errore'
|
|
@@ -362,14 +505,80 @@ console.log(user.name)
|
|
|
362
505
|
| Zig | `!?T` (error union + optional) | Yes, specific syntax |
|
|
363
506
|
| **errore** | `Error \| T \| null` | **No!** Check in any order |
|
|
364
507
|
|
|
365
|
-
With errore
|
|
508
|
+
With errore you **check in any order**:
|
|
366
509
|
- Use `?.` and `??` naturally
|
|
367
510
|
- Check `instanceof Error` or `=== null` in any order
|
|
368
511
|
- No unwrapping ceremony
|
|
369
512
|
- TypeScript infers everything
|
|
370
513
|
|
|
514
|
+
## Why This Is Better Than Go
|
|
515
|
+
|
|
516
|
+
Go's error handling uses **two separate return values**:
|
|
517
|
+
|
|
518
|
+
```go
|
|
519
|
+
user, err := fetchUser(id)
|
|
520
|
+
// Oops! Forgot to check err
|
|
521
|
+
fmt.Println(user.Name) // Compiles fine, crashes at runtime
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
The compiler can't save you here. You can ignore `err` entirely and use `user` directly.
|
|
525
|
+
|
|
526
|
+
With errore, **forgetting to check is impossible**:
|
|
527
|
+
|
|
528
|
+
```ts
|
|
529
|
+
const user = await fetchUser(id) // type: NotFoundError | User
|
|
530
|
+
|
|
531
|
+
console.log(user.id) // TS Error: Property 'id' does not exist on type 'NotFoundError'
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
Since errore uses a **single union variable** instead of two separate values, TypeScript forces you to narrow the type before accessing value-specific properties. You literally cannot use the value without first doing an `instanceof Error` check.
|
|
535
|
+
|
|
536
|
+
> **Note:** Properties that exist on both `Error` and your value type (like `name`, `message`) can still be accessed without narrowing. This is a small set of 4 fields: `name`, `message`, `stack`, `cause`.
|
|
537
|
+
|
|
538
|
+
### The Remaining Gap
|
|
539
|
+
|
|
540
|
+
There's still one case errore can't catch: **ignored return values**:
|
|
541
|
+
|
|
542
|
+
```ts
|
|
543
|
+
// Oops! Completely ignoring the return value
|
|
544
|
+
updateUser(id, data) // No error, but we should check!
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
For this, use **TypeScript's built-in checks** or a linter:
|
|
548
|
+
|
|
549
|
+
**TypeScript `tsconfig.json`:**
|
|
550
|
+
```json
|
|
551
|
+
{
|
|
552
|
+
"compilerOptions": {
|
|
553
|
+
"noUnusedLocals": true
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
This catches unused variables, though not ignored return values directly.
|
|
559
|
+
|
|
560
|
+
**oxlint `no-unused-expressions`:**
|
|
561
|
+
|
|
562
|
+
`oxlint.json`:
|
|
563
|
+
```json
|
|
564
|
+
{
|
|
565
|
+
"rules": {
|
|
566
|
+
"no-unused-expressions": "error"
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
Or via CLI:
|
|
572
|
+
```bash
|
|
573
|
+
oxlint --deny no-unused-expressions
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
Combined with errore's type safety, these tools give you near-complete protection against ignored errors.
|
|
577
|
+
|
|
371
578
|
## Comparison with Result Types
|
|
372
579
|
|
|
580
|
+
**Direct returns** vs wrapper methods:
|
|
581
|
+
|
|
373
582
|
| Result Pattern | errore |
|
|
374
583
|
|---------------|--------|
|
|
375
584
|
| `Result.ok(value)` | just `return value` |
|
|
@@ -379,9 +588,150 @@ With errore:
|
|
|
379
588
|
| `Result<User, Error>` | `Error \| User` |
|
|
380
589
|
| `Result<Option<T>, E>` | `Error \| T \| null` |
|
|
381
590
|
|
|
591
|
+
## Vs neverthrow / better-result
|
|
592
|
+
|
|
593
|
+
These libraries wrap values in a **Result container**. You construct results with `ok()` and `err()`, then unwrap them with `.value` and `.error`:
|
|
594
|
+
|
|
595
|
+
```ts
|
|
596
|
+
// neverthrow
|
|
597
|
+
import { ok, err, Result } from 'neverthrow'
|
|
598
|
+
|
|
599
|
+
function getUser(id: string): Result<User, NotFoundError> {
|
|
600
|
+
const user = db.find(id)
|
|
601
|
+
if (!user) return err(new NotFoundError({ id }))
|
|
602
|
+
return ok(user) // must wrap
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const result = getUser('123')
|
|
606
|
+
if (result.isErr()) {
|
|
607
|
+
console.log(result.error) // must unwrap
|
|
608
|
+
return
|
|
609
|
+
}
|
|
610
|
+
console.log(result.value.name) // must unwrap
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
```ts
|
|
614
|
+
// errore
|
|
615
|
+
function getUser(id: string): User | NotFoundError {
|
|
616
|
+
const user = db.find(id)
|
|
617
|
+
if (!user) return new NotFoundError({ id })
|
|
618
|
+
return user // just return
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
const user = getUser('123')
|
|
622
|
+
if (user instanceof Error) {
|
|
623
|
+
console.log(user) // it's already the error
|
|
624
|
+
return
|
|
625
|
+
}
|
|
626
|
+
console.log(user.name) // it's already the user
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
**The key insight**: `T | Error` already encodes success/failure. TypeScript's type narrowing does the rest. No wrapper needed.
|
|
630
|
+
|
|
631
|
+
| Feature | neverthrow | errore |
|
|
632
|
+
|---------|------------|--------|
|
|
633
|
+
| Type-safe errors | ✓ | ✓ |
|
|
634
|
+
| Exhaustive handling | ✓ | ✓ |
|
|
635
|
+
| Works with null | `Result<T \| null, E>` | `T \| E \| null` |
|
|
636
|
+
| Learning curve | New API (`ok`, `err`, `map`, `andThen`, ...) | Just `instanceof` |
|
|
637
|
+
| Bundle size | ~3KB min | **~0 bytes** |
|
|
638
|
+
| Interop | Requires wrapping/unwrapping at boundaries | Native TypeScript |
|
|
639
|
+
|
|
640
|
+
neverthrow also requires an [eslint plugin](https://github.com/mdbetancourt/eslint-plugin-neverthrow) to catch unhandled results. With errore, TypeScript itself prevents you from using a value without checking the error first.
|
|
641
|
+
|
|
642
|
+
## Vs Effect.ts
|
|
643
|
+
|
|
644
|
+
Effect is not just error handling—it's a **complete functional programming framework** with dependency injection, concurrency primitives, resource management, streaming, and more.
|
|
645
|
+
|
|
646
|
+
```ts
|
|
647
|
+
// Effect.ts - a paradigm shift
|
|
648
|
+
import { Effect, pipe } from 'effect'
|
|
649
|
+
|
|
650
|
+
const program = pipe(
|
|
651
|
+
fetchUser(id),
|
|
652
|
+
Effect.flatMap(user => fetchPosts(user.id)),
|
|
653
|
+
Effect.map(posts => posts.filter(p => p.published)),
|
|
654
|
+
Effect.catchTag('NotFoundError', () => Effect.succeed([]))
|
|
655
|
+
)
|
|
656
|
+
|
|
657
|
+
const result = await Effect.runPromise(program)
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
```ts
|
|
661
|
+
// errore - regular TypeScript
|
|
662
|
+
const user = await fetchUser(id)
|
|
663
|
+
if (user instanceof Error) return []
|
|
664
|
+
|
|
665
|
+
const posts = await fetchPosts(user.id)
|
|
666
|
+
if (posts instanceof Error) return []
|
|
667
|
+
|
|
668
|
+
return posts.filter(p => p.published)
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
Effect is powerful if you need its full feature set. But if you just want type-safe errors:
|
|
672
|
+
|
|
673
|
+
| | Effect | errore |
|
|
674
|
+
|-|--------|--------|
|
|
675
|
+
| Learning curve | Steep (new paradigm) | Minimal (just `instanceof`) |
|
|
676
|
+
| Codebase impact | Pervasive (everything becomes an Effect) | Surgical (adopt incrementally) |
|
|
677
|
+
| Bundle size | ~50KB+ | **~0 bytes** |
|
|
678
|
+
| Use case | Full FP framework | Just error handling |
|
|
679
|
+
|
|
680
|
+
**Use Effect** when you want dependency injection, structured concurrency, and the full functional programming experience.
|
|
681
|
+
|
|
682
|
+
**Use errore** when you just want type-safe errors without rewriting your codebase.
|
|
683
|
+
|
|
684
|
+
## Zero-Dependency Philosophy
|
|
685
|
+
|
|
686
|
+
errore is more a **way of writing code** than a library. The core pattern requires nothing:
|
|
687
|
+
|
|
688
|
+
```ts
|
|
689
|
+
// You can write this without installing errore at all
|
|
690
|
+
class NotFoundError extends Error {
|
|
691
|
+
readonly _tag = 'NotFoundError'
|
|
692
|
+
constructor(public id: string) {
|
|
693
|
+
super(`User ${id} not found`)
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
async function getUser(id: string): Promise<User | NotFoundError> {
|
|
698
|
+
const user = await db.find(id)
|
|
699
|
+
if (!user) return new NotFoundError(id)
|
|
700
|
+
return user
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const user = await getUser('123')
|
|
704
|
+
if (user instanceof Error) return user
|
|
705
|
+
console.log(user.name)
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
The `errore` package just provides conveniences: `createTaggedError` for less boilerplate, `matchError` for exhaustive pattern matching, `tryAsync` for catching exceptions. But the core pattern—**errors as union types**—works with zero dependencies.
|
|
709
|
+
|
|
710
|
+
### Perfect for Libraries
|
|
711
|
+
|
|
712
|
+
Ideal for library authors. Return **plain TypeScript unions** instead of forcing users to adopt your error handling framework:
|
|
713
|
+
|
|
714
|
+
```ts
|
|
715
|
+
// ❌ Library that forces a dependency on users
|
|
716
|
+
import { Result } from 'some-result-lib'
|
|
717
|
+
export function parse(input: string): Result<AST, ParseError>
|
|
718
|
+
|
|
719
|
+
// Users must now install and learn 'some-result-lib'
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
```ts
|
|
723
|
+
// ✓ Library using plain TypeScript unions
|
|
724
|
+
export function parse(input: string): AST | ParseError
|
|
725
|
+
|
|
726
|
+
// Users handle errors with standard instanceof checks
|
|
727
|
+
// No new dependencies, no new concepts to learn
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
Your library stays lightweight. Users get type-safe errors without adopting an opinionated wrapper. Everyone wins.
|
|
731
|
+
|
|
382
732
|
## Import Style
|
|
383
733
|
|
|
384
|
-
> **Note:** Always use `import * as errore from 'errore'` instead of named imports. This makes code easier to move between files, and more readable
|
|
734
|
+
> **Note:** Always use `import * as errore from 'errore'` instead of named imports. This makes code easier to move between files, and more readable since every function call is **clearly namespaced** (e.g. `errore.isOk()` instead of just `isOk()`).
|
|
385
735
|
|
|
386
736
|
## License
|
|
387
737
|
|
package/dist/error.d.ts
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walk the .cause chain of an error to find an ancestor matching a specific error class.
|
|
3
|
+
* Checks the error itself first, then traverses .cause recursively.
|
|
4
|
+
* Similar to Go's `errors.As`.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const notFound = findCause(err, NotFoundError)
|
|
8
|
+
* if (notFound) {
|
|
9
|
+
* console.log(notFound.id) // type-safe access
|
|
10
|
+
* }
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // With optional chaining
|
|
14
|
+
* const id = findCause(err, NotFoundError)?.id
|
|
15
|
+
*/
|
|
16
|
+
export declare function findCause<T extends Error>(error: Error, ErrorClass: new (...args: any[]) => T): T | undefined;
|
|
1
17
|
/**
|
|
2
18
|
* Any tagged error (for generic constraints)
|
|
3
19
|
*/
|
|
@@ -14,6 +30,8 @@ type ErrorClass = new (...args: any[]) => Error;
|
|
|
14
30
|
export type TaggedErrorInstance<Tag extends string, Props, Base extends Error = Error> = Base & {
|
|
15
31
|
readonly _tag: Tag;
|
|
16
32
|
toJSON(): object;
|
|
33
|
+
/** Walk the .cause chain to find an ancestor matching a specific error class. */
|
|
34
|
+
findCause<T extends Error>(ErrorClass: new (...args: any[]) => T): T | undefined;
|
|
17
35
|
} & Readonly<Props>;
|
|
18
36
|
/**
|
|
19
37
|
* Class type produced by TaggedError factory
|
package/dist/error.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"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"}
|
package/dist/error.js
CHANGED
|
@@ -7,6 +7,34 @@ const serializeCause = (cause) => {
|
|
|
7
7
|
}
|
|
8
8
|
return cause;
|
|
9
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* Walk the .cause chain of an error to find an ancestor matching a specific error class.
|
|
12
|
+
* Checks the error itself first, then traverses .cause recursively.
|
|
13
|
+
* Similar to Go's `errors.As`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const notFound = findCause(err, NotFoundError)
|
|
17
|
+
* if (notFound) {
|
|
18
|
+
* console.log(notFound.id) // type-safe access
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // With optional chaining
|
|
23
|
+
* const id = findCause(err, NotFoundError)?.id
|
|
24
|
+
*/
|
|
25
|
+
export function findCause(error, ErrorClass) {
|
|
26
|
+
const seen = new Set();
|
|
27
|
+
let current = error;
|
|
28
|
+
while (current instanceof Error) {
|
|
29
|
+
if (seen.has(current))
|
|
30
|
+
break;
|
|
31
|
+
seen.add(current);
|
|
32
|
+
if (current instanceof ErrorClass)
|
|
33
|
+
return current;
|
|
34
|
+
current = current.cause;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
10
38
|
/**
|
|
11
39
|
* Type guard for any tagged error
|
|
12
40
|
*/
|
|
@@ -71,6 +99,9 @@ export const TaggedError = Object.assign((tag, BaseClass) => () => {
|
|
|
71
99
|
this.stack = `${this.stack}\nCaused by: ${indented}`;
|
|
72
100
|
}
|
|
73
101
|
}
|
|
102
|
+
findCause(ErrorClass) {
|
|
103
|
+
return findCause(this, ErrorClass);
|
|
104
|
+
}
|
|
74
105
|
toJSON() {
|
|
75
106
|
return {
|
|
76
107
|
...this,
|
package/dist/factory.d.ts
CHANGED
|
@@ -62,6 +62,8 @@ export type FactoryTaggedErrorInstance<Tag extends string, Msg extends string, B
|
|
|
62
62
|
readonly _tag: Tag;
|
|
63
63
|
readonly message: string;
|
|
64
64
|
toJSON(): object;
|
|
65
|
+
/** Walk the .cause chain to find an ancestor matching a specific error class. */
|
|
66
|
+
findCause<T extends Error>(ErrorClass: new (...args: any[]) => T): T | undefined;
|
|
65
67
|
} & Readonly<VarProps<Msg>>;
|
|
66
68
|
/**
|
|
67
69
|
* Class type returned by createTaggedError factory.
|
package/dist/factory.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"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"}
|
package/dist/factory.js
CHANGED
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Factory API for creating tagged errors with $variable interpolation in messages.
|
|
3
|
-
*
|
|
4
|
-
* Extracts variable names from the message template and requires them in the constructor.
|
|
5
|
-
* Use `class X extends createTaggedError({...}) {}` so X is both a value and a type.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* class NotFoundError extends createTaggedError({
|
|
9
|
-
* name: 'NotFoundError',
|
|
10
|
-
* message: 'User $id not found in $database'
|
|
11
|
-
* }) {}
|
|
12
|
-
*
|
|
13
|
-
* throw new NotFoundError({ id: '123', database: 'users' })
|
|
14
|
-
* // err._tag = 'NotFoundError'
|
|
15
|
-
* // err.message = 'User 123 not found in users'
|
|
16
|
-
* // err.id = '123'
|
|
17
|
-
* // err.database = 'users'
|
|
18
|
-
*/
|
|
1
|
+
import { findCause } from './error.js';
|
|
19
2
|
/**
|
|
20
3
|
* Serialize cause for JSON output
|
|
21
4
|
*/
|
|
@@ -143,6 +126,9 @@ export function createTaggedError(opts) {
|
|
|
143
126
|
this.stack = `${this.stack}\nCaused by: ${indented}`;
|
|
144
127
|
}
|
|
145
128
|
}
|
|
129
|
+
findCause(ErrorClass) {
|
|
130
|
+
return findCause(this, ErrorClass);
|
|
131
|
+
}
|
|
146
132
|
toJSON() {
|
|
147
133
|
const json = {
|
|
148
134
|
_tag: this._tag,
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export type { Errore, InferError, InferValue, EnsureNotError } from './types.js'
|
|
|
2
2
|
export { isError, isOk, tryFn, tryFn as try, tryAsync } from './core.js';
|
|
3
3
|
export { map, mapError, andThen, andThenAsync, tap, tapAsync } from './transform.js';
|
|
4
4
|
export { unwrap, unwrapOr, match, partition, flatten } from './extract.js';
|
|
5
|
-
export { TaggedError, matchError, matchErrorPartial, isTaggedError, UnhandledError } from './error.js';
|
|
5
|
+
export { TaggedError, matchError, matchErrorPartial, isTaggedError, UnhandledError, findCause } from './error.js';
|
|
6
6
|
export type { TaggedErrorInstance, TaggedErrorClass } from './error.js';
|
|
7
7
|
export { createTaggedError } from './factory.js';
|
|
8
8
|
export type { FactoryTaggedErrorClass, FactoryTaggedErrorInstance } from './factory.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAGhF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGxE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAGpF,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAG1E,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAGhF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGxE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAGpF,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAG1E,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACjH,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAGvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,YAAY,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,6 @@ export { map, mapError, andThen, andThenAsync, tap, tapAsync } from './transform
|
|
|
5
5
|
// Extraction
|
|
6
6
|
export { unwrap, unwrapOr, match, partition, flatten } from './extract.js';
|
|
7
7
|
// Tagged errors
|
|
8
|
-
export { TaggedError, matchError, matchErrorPartial, isTaggedError, UnhandledError } from './error.js';
|
|
8
|
+
export { TaggedError, matchError, matchErrorPartial, isTaggedError, UnhandledError, findCause } from './error.js';
|
|
9
9
|
// Factory API for tagged errors with $variable interpolation
|
|
10
10
|
export { createTaggedError } from './factory.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|