errore 0.4.1 → 0.5.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 CHANGED
@@ -237,6 +237,14 @@ const message = matchError(error, {
237
237
  })
238
238
  console.log(message)
239
239
 
240
+ // Handle plain Error with _ (underscore) handler
241
+ function riskyOp(): ValidationError | Error { ... }
242
+ const err = riskyOp()
243
+ const msg = matchError(err, {
244
+ ValidationError: e => `Invalid ${e.field}`,
245
+ _: e => `Plain error: ${e.message}` // catches non-tagged Error
246
+ })
247
+
240
248
  // Partial matching with fallback
241
249
  const fallbackMsg = matchErrorPartial(error, {
242
250
  ValidationError: e => `Invalid ${e.field}`
package/dist/index.d.mts CHANGED
@@ -71,23 +71,34 @@ declare const TaggedError: {
71
71
  */
72
72
  declare const isTaggedError: (value: unknown) => value is AnyTaggedError;
73
73
  /**
74
- * Handler map for exhaustive matching
74
+ * Handler map that includes `_` for plain Error (untagged)
75
75
  */
76
- type MatchHandlers<E extends AnyTaggedError, R> = {
77
- [K in E['_tag']]: (err: Extract<E, {
76
+ type MatchHandlersWithPlain<E extends Error, R> = {
77
+ [K in Extract<E, AnyTaggedError>['_tag']]: (err: Extract<E, {
78
78
  _tag: K;
79
79
  }>) => R;
80
- };
80
+ } & (Exclude<E, AnyTaggedError> extends never ? {} : {
81
+ _: (err: Exclude<E, AnyTaggedError>) => R;
82
+ });
81
83
  /**
82
- * Exhaustive pattern match on tagged error union by _tag.
84
+ * Exhaustive pattern match on error union by _tag.
85
+ * Use `_` handler for plain Error instances without _tag.
83
86
  *
84
87
  * @example
88
+ * // Tagged errors only
85
89
  * matchError(err, {
86
90
  * NotFoundError: (e) => `Missing: ${e.id}`,
87
91
  * ValidationError: (e) => `Invalid: ${e.field}`,
88
92
  * });
93
+ *
94
+ * @example
95
+ * // Mixed tagged and plain Error
96
+ * matchError(err, {
97
+ * NotFoundError: (e) => `Missing: ${e.id}`,
98
+ * _: (e) => `Unknown error: ${e.message}`,
99
+ * });
89
100
  */
90
- declare function matchError<E extends AnyTaggedError, R>(err: E, handlers: MatchHandlers<E, R>): R;
101
+ declare function matchError<E extends Error, R>(err: E, handlers: MatchHandlersWithPlain<E, R>): R;
91
102
  /**
92
103
  * Partial pattern match with fallback for unhandled tags.
93
104
  *
@@ -96,7 +107,7 @@ declare function matchError<E extends AnyTaggedError, R>(err: E, handlers: Match
96
107
  * NotFoundError: (e) => `Missing: ${e.id}`,
97
108
  * }, (e) => `Unknown: ${e.message}`);
98
109
  */
99
- declare function matchErrorPartial<E extends AnyTaggedError, R>(err: E, handlers: Partial<MatchHandlers<E, R>>, fallback: (e: E) => R): R;
110
+ declare function matchErrorPartial<E extends Error, R>(err: E, handlers: Partial<MatchHandlersWithPlain<E, R>>, fallback: (e: E) => R): R;
100
111
  declare const UnhandledError_base: TaggedErrorClass<"UnhandledError", {
101
112
  message: string;
102
113
  cause: unknown;
package/dist/index.d.ts CHANGED
@@ -71,23 +71,34 @@ declare const TaggedError: {
71
71
  */
72
72
  declare const isTaggedError: (value: unknown) => value is AnyTaggedError;
73
73
  /**
74
- * Handler map for exhaustive matching
74
+ * Handler map that includes `_` for plain Error (untagged)
75
75
  */
76
- type MatchHandlers<E extends AnyTaggedError, R> = {
77
- [K in E['_tag']]: (err: Extract<E, {
76
+ type MatchHandlersWithPlain<E extends Error, R> = {
77
+ [K in Extract<E, AnyTaggedError>['_tag']]: (err: Extract<E, {
78
78
  _tag: K;
79
79
  }>) => R;
80
- };
80
+ } & (Exclude<E, AnyTaggedError> extends never ? {} : {
81
+ _: (err: Exclude<E, AnyTaggedError>) => R;
82
+ });
81
83
  /**
82
- * Exhaustive pattern match on tagged error union by _tag.
84
+ * Exhaustive pattern match on error union by _tag.
85
+ * Use `_` handler for plain Error instances without _tag.
83
86
  *
84
87
  * @example
88
+ * // Tagged errors only
85
89
  * matchError(err, {
86
90
  * NotFoundError: (e) => `Missing: ${e.id}`,
87
91
  * ValidationError: (e) => `Invalid: ${e.field}`,
88
92
  * });
93
+ *
94
+ * @example
95
+ * // Mixed tagged and plain Error
96
+ * matchError(err, {
97
+ * NotFoundError: (e) => `Missing: ${e.id}`,
98
+ * _: (e) => `Unknown error: ${e.message}`,
99
+ * });
89
100
  */
90
- declare function matchError<E extends AnyTaggedError, R>(err: E, handlers: MatchHandlers<E, R>): R;
101
+ declare function matchError<E extends Error, R>(err: E, handlers: MatchHandlersWithPlain<E, R>): R;
91
102
  /**
92
103
  * Partial pattern match with fallback for unhandled tags.
93
104
  *
@@ -96,7 +107,7 @@ declare function matchError<E extends AnyTaggedError, R>(err: E, handlers: Match
96
107
  * NotFoundError: (e) => `Missing: ${e.id}`,
97
108
  * }, (e) => `Unknown: ${e.message}`);
98
109
  */
99
- declare function matchErrorPartial<E extends AnyTaggedError, R>(err: E, handlers: Partial<MatchHandlers<E, R>>, fallback: (e: E) => R): R;
110
+ declare function matchErrorPartial<E extends Error, R>(err: E, handlers: Partial<MatchHandlersWithPlain<E, R>>, fallback: (e: E) => R): R;
100
111
  declare const UnhandledError_base: TaggedErrorClass<"UnhandledError", {
101
112
  message: string;
102
113
  cause: unknown;
package/dist/index.js CHANGED
@@ -93,13 +93,30 @@ Caused by: ${indented}`;
93
93
  );
94
94
  var isTaggedError = isAnyTaggedError;
95
95
  function matchError(err, handlers) {
96
- const handler = handlers[err._tag];
97
- return handler(err);
96
+ const h = handlers;
97
+ if ("_tag" in err && typeof err._tag === "string") {
98
+ const handler = h[err._tag];
99
+ if (handler) {
100
+ return handler(err);
101
+ }
102
+ }
103
+ const fallbackHandler = h["_"];
104
+ if (fallbackHandler) {
105
+ return fallbackHandler(err);
106
+ }
107
+ throw new Error(`No handler for error: ${err.message}`);
98
108
  }
99
109
  function matchErrorPartial(err, handlers, fallback) {
100
- const handler = handlers[err._tag];
101
- if (handler) {
102
- return handler(err);
110
+ const h = handlers;
111
+ if ("_tag" in err && typeof err._tag === "string") {
112
+ const handler = h[err._tag];
113
+ if (handler) {
114
+ return handler(err);
115
+ }
116
+ }
117
+ const underscoreHandler = h["_"];
118
+ if (underscoreHandler) {
119
+ return underscoreHandler(err);
103
120
  }
104
121
  return fallback(err);
105
122
  }
package/dist/index.mjs CHANGED
@@ -48,13 +48,30 @@ Caused by: ${indented}`;
48
48
  );
49
49
  var isTaggedError = isAnyTaggedError;
50
50
  function matchError(err, handlers) {
51
- const handler = handlers[err._tag];
52
- return handler(err);
51
+ const h = handlers;
52
+ if ("_tag" in err && typeof err._tag === "string") {
53
+ const handler = h[err._tag];
54
+ if (handler) {
55
+ return handler(err);
56
+ }
57
+ }
58
+ const fallbackHandler = h["_"];
59
+ if (fallbackHandler) {
60
+ return fallbackHandler(err);
61
+ }
62
+ throw new Error(`No handler for error: ${err.message}`);
53
63
  }
54
64
  function matchErrorPartial(err, handlers, fallback) {
55
- const handler = handlers[err._tag];
56
- if (handler) {
57
- return handler(err);
65
+ const h = handlers;
66
+ if ("_tag" in err && typeof err._tag === "string") {
67
+ const handler = h[err._tag];
68
+ if (handler) {
69
+ return handler(err);
70
+ }
71
+ }
72
+ const underscoreHandler = h["_"];
73
+ if (underscoreHandler) {
74
+ return underscoreHandler(err);
58
75
  }
59
76
  return fallback(err);
60
77
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "errore",
3
- "version": "0.4.1",
3
+ "version": "0.5.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",