@consolidados/results 0.3.0 → 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.
Files changed (42) hide show
  1. package/README.md +129 -10
  2. package/dist/helpers/match.cjs +24 -42
  3. package/dist/helpers/match.cjs.map +1 -1
  4. package/dist/helpers/match.d.cts +9 -17
  5. package/dist/helpers/match.d.ts +9 -17
  6. package/dist/helpers/match.js +24 -42
  7. package/dist/helpers/match.js.map +1 -1
  8. package/dist/index.cjs +41 -46
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +1 -1
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +41 -46
  13. package/dist/index.js.map +1 -1
  14. package/dist/option/index.cjs +17 -4
  15. package/dist/option/index.cjs.map +1 -1
  16. package/dist/option/index.d.cts +1 -1
  17. package/dist/option/index.d.ts +1 -1
  18. package/dist/option/index.js +17 -4
  19. package/dist/option/index.js.map +1 -1
  20. package/dist/option/option.cjs +17 -4
  21. package/dist/option/option.cjs.map +1 -1
  22. package/dist/option/option.d.cts +2 -2
  23. package/dist/option/option.d.ts +2 -2
  24. package/dist/option/option.js +17 -4
  25. package/dist/option/option.js.map +1 -1
  26. package/dist/{option-B_KKIecf.d.cts → option-CYCiGxtw.d.cts} +13 -0
  27. package/dist/{option-B_KKIecf.d.ts → option-CYCiGxtw.d.ts} +13 -0
  28. package/dist/result/index.cjs +9 -2
  29. package/dist/result/index.cjs.map +1 -1
  30. package/dist/result/index.d.cts +1 -1
  31. package/dist/result/index.d.ts +1 -1
  32. package/dist/result/index.js +9 -2
  33. package/dist/result/index.js.map +1 -1
  34. package/dist/result/result.cjs +9 -2
  35. package/dist/result/result.cjs.map +1 -1
  36. package/dist/result/result.d.cts +2 -2
  37. package/dist/result/result.d.ts +2 -2
  38. package/dist/result/result.js +9 -2
  39. package/dist/result/result.js.map +1 -1
  40. package/dist/types/globals.d.cts +9 -17
  41. package/dist/types/globals.d.ts +9 -17
  42. package/package.json +3 -4
package/README.md CHANGED
@@ -11,7 +11,7 @@ This package provides robust implementations of the `Result` and `Option` types,
11
11
  - 🎯 **Type-safe** - Full TypeScript support with type narrowing
12
12
  - 🚀 **Performance** - None singleton pattern (95% less allocations)
13
13
  - 🔄 **Flexible** - Support for any error type (enums, strings, custom classes)
14
- - 🎨 **Pattern matching** - Match primitives, enums, and discriminated unions
14
+ - 🎨 **Pattern matching** - Match primitives, enums, discriminated unions, and mixed primitive + object unions
15
15
  - 🛠️ **Rich API** - unwrapOr, orElse, filter, and more
16
16
  - 🌍 **Global availability** - Optional global imports for cleaner code
17
17
 
@@ -48,6 +48,71 @@ const result = Ok(42);
48
48
  const option = Some("hello");
49
49
  ```
50
50
 
51
+ ### Monorepo / workspace setup
52
+
53
+ In a monorepo (Turborepo, Nx, pnpm workspaces, etc.) you usually don't want
54
+ to repeat the global wiring in every `tsconfig.json` and every entrypoint.
55
+ Wrap it once in a shared types package and have the other workspaces depend
56
+ on that.
57
+
58
+ **1. Create a shared package, e.g. `packages/types`:**
59
+
60
+ `packages/types/src/globals.ts` — runtime side-effect (registers
61
+ `Ok`, `Err`, `Some`, `None`, `match` on `globalThis`):
62
+
63
+ ```typescript
64
+ import "@consolidados/results";
65
+ ```
66
+
67
+ `packages/types/src/globals-types.d.ts` — ambient TypeScript types so
68
+ `Result<T, E>` and `Option<T>` work without per-file imports:
69
+
70
+ ```typescript
71
+ import type { Option as _Option, Result as _Result } from "@consolidados/results";
72
+
73
+ declare global {
74
+ type Result<T, E> = _Result<T, E>;
75
+ type Option<T> = _Option<T>;
76
+ }
77
+
78
+ export {};
79
+ ```
80
+
81
+ `packages/types/package.json` — expose both as subpath exports:
82
+
83
+ ```json
84
+ {
85
+ "name": "@your-org/types",
86
+ "dependencies": { "@consolidados/results": "^0.5.0" },
87
+ "exports": {
88
+ "./globals": "./src/globals.ts",
89
+ "./globals-types": "./src/globals-types.d.ts"
90
+ }
91
+ }
92
+ ```
93
+
94
+ **2. In each consuming workspace:**
95
+
96
+ `services/<name>/tsconfig.json`:
97
+
98
+ ```json
99
+ {
100
+ "compilerOptions": {
101
+ "types": ["node", "@your-org/types/globals-types"]
102
+ }
103
+ }
104
+ ```
105
+
106
+ `services/<name>/src/main.ts` (first import of the entrypoint):
107
+
108
+ ```typescript
109
+ import "@your-org/types/globals";
110
+ ```
111
+
112
+ Now every file in that workspace can use `Ok`, `Err`, `Some`, `None`, `match`,
113
+ `Result<T, E>`, and `Option<T>` without any import — and the wiring lives in
114
+ one place.
115
+
51
116
  ## Quick Start
52
117
 
53
118
  ### Result - Handle Success/Failure
@@ -150,8 +215,8 @@ var APIError;
150
215
  ```typescript
151
216
  const APIError = {
152
217
  NotFound: "NOT_FOUND",
153
- Unauthorized = "UNAUTHORIZED",
154
- ServerError = "SERVER_ERROR",
218
+ Unauthorized: "UNAUTHORIZED",
219
+ ServerError: "SERVER_ERROR",
155
220
  } as const;
156
221
 
157
222
  type APIError = (typeof APIError)[keyof typeof APIError];
@@ -390,6 +455,49 @@ const simplified = match(status, {
390
455
  });
391
456
  ```
392
457
 
458
+ ### Matching Mixed Primitive + Object Unions
459
+
460
+ Unions that combine primitive strings and object variants (common in Rust-style error types):
461
+
462
+ ```typescript
463
+ type ServiceError =
464
+ | "ConnectionFailed"
465
+ | "InvalidConfiguration"
466
+ | { Other: [string, string] };
467
+
468
+ const err: ServiceError = { Other: ["reason", "detail"] };
469
+
470
+ // Exhaustive - all cases required
471
+ const message = match(err, {
472
+ ConnectionFailed: () => "Connection failed",
473
+ InvalidConfiguration: () => "Invalid config",
474
+ Other: (data) => `Other error: ${data[0]} - ${data[1]}`,
475
+ });
476
+
477
+ // With default - partial cases allowed
478
+ const simplified = match(err, {
479
+ ConnectionFailed: () => "Connection issue",
480
+ default: () => "Something else happened",
481
+ });
482
+ ```
483
+
484
+ Also works with complex object properties:
485
+
486
+ ```typescript
487
+ type AppError =
488
+ | "NotFound"
489
+ | { Details: { code: number; message: string } }
490
+ | { Metadata: string[] };
491
+
492
+ const error: AppError = { Details: { code: 404, message: "Not found" } };
493
+
494
+ const result = match(error, {
495
+ NotFound: () => "Not found",
496
+ Details: (details) => `Error ${details.code}: ${details.message}`,
497
+ Metadata: (meta) => meta.join(", "),
498
+ });
499
+ ```
500
+
393
501
  ### Matching Discriminated Unions
394
502
 
395
503
  ```typescript
@@ -451,13 +559,12 @@ const result = await fetchUser(123);
451
559
 
452
560
  const message = match(result, {
453
561
  Ok: (user) => `Welcome, ${user.name}!`,
454
- Err: (error) => {
455
- // Match on string values (const object compiles to strings)
456
- const errMsg = (error as any).message || String(error);
457
- if (errMsg.includes("NOT_FOUND")) return "User not found";
458
- if (errMsg.includes("UNAUTHORIZED")) return "Please login";
459
- return "Server error, try again";
460
- },
562
+ Err: (error) =>
563
+ match(error, {
564
+ NOT_FOUND: () => "User not found",
565
+ UNAUTHORIZED: () => "Please login",
566
+ SERVER_ERROR: () => "Server error, try again",
567
+ }),
461
568
  });
462
569
  ```
463
570
 
@@ -602,6 +709,18 @@ match<T extends string | number | symbol, R>(
602
709
  cases: { [K in T]?: () => R } & { default: () => R }
603
710
  ): R
604
711
 
712
+ // Mixed primitive + object union (exhaustive)
713
+ match<T extends PropertyKey | object, R>(
714
+ matcher: T,
715
+ cases: MatchCases<T, R, false>
716
+ ): R
717
+
718
+ // Mixed primitive + object union (with default)
719
+ match<T extends PropertyKey | object, R>(
720
+ matcher: T,
721
+ cases: MatchCases<T, R, true>
722
+ ): R
723
+
605
724
  // Discriminated union matching
606
725
  match<T, D extends keyof T, R>(
607
726
  matcher: T,
@@ -1,63 +1,45 @@
1
1
  'use strict';
2
2
 
3
3
  // src/helpers/match.ts
4
+ var TAG = Symbol.for("@consolidados/results.tag");
4
5
  function match(matcher, cases, discriminant) {
5
- if (typeof matcher === "string" || typeof matcher === "number" || typeof matcher === "symbol") {
6
+ const t = typeof matcher;
7
+ if (t === "string" || t === "number" || t === "symbol") {
6
8
  const handler = cases[matcher];
7
- if (handler) {
9
+ if (handler) return handler();
10
+ if (cases.default) return cases.default();
11
+ throw new Error(`No case found for value: ${String(matcher)}`);
12
+ }
13
+ if (matcher !== null && t === "object") {
14
+ const tag = matcher[TAG];
15
+ if (tag !== void 0) {
16
+ const handler = cases[tag];
17
+ if (!handler) throw new Error(`Missing case for ${tag}`);
18
+ if (tag === "Ok" || tag === "Some") return handler(matcher.unwrap());
19
+ if (tag === "Err") return handler(matcher.unwrapErr());
8
20
  return handler();
9
21
  }
10
- if (cases.default) {
11
- return cases.default();
22
+ if (discriminant) {
23
+ const dv = matcher[discriminant];
24
+ const handler = cases[dv];
25
+ if (handler) return handler(matcher);
26
+ if (cases.default) return cases.default(matcher);
27
+ throw new Error(`No case found for discriminant value: ${String(dv)}`);
12
28
  }
13
- throw new Error(`No case found for value: ${String(matcher)}`);
14
- }
15
- if (typeof matcher === "object" && matcher !== null && !discriminant) {
16
- for (const key in cases) {
29
+ for (const key in matcher) {
17
30
  if (key === "default") continue;
18
- if (key in matcher) {
31
+ if (key in cases) {
19
32
  const handler = cases[key];
20
33
  if (handler) {
21
34
  return typeof handler === "function" ? handler(matcher[key]) : handler();
22
35
  }
23
36
  }
24
37
  }
25
- if (cases.default) {
26
- return cases.default();
27
- }
28
- }
29
- if (discriminant && typeof matcher === "object" && matcher !== null) {
30
- const discriminantValue = matcher[discriminant];
31
- const handler = cases[discriminantValue];
32
- if (handler) {
33
- return handler(matcher);
34
- }
35
- if (cases.default) {
36
- return cases.default(matcher);
37
- }
38
- throw new Error(
39
- `No case found for discriminant value: ${String(discriminantValue)}`
40
- );
41
- }
42
- if (typeof matcher === "object" && matcher !== null && "isOk" in matcher && matcher.isOk()) {
43
- if (!cases.Ok) throw new Error("Missing case for Ok");
44
- return cases.Ok(matcher.unwrap());
45
- }
46
- if (typeof matcher === "object" && matcher !== null && "isErr" in matcher && matcher.isErr()) {
47
- if (!cases.Err) throw new Error("Missing case for Err");
48
- return cases.Err(matcher.unwrapErr());
49
- }
50
- if (typeof matcher === "object" && matcher !== null && "isSome" in matcher && matcher.isSome()) {
51
- if (!cases.Some) throw new Error("Missing case for Some");
52
- return cases.Some(matcher.unwrap());
53
- }
54
- if (typeof matcher === "object" && matcher !== null && "isNone" in matcher && matcher.isNone()) {
55
- if (!cases.None) throw new Error("Missing case for None");
56
- return cases.None();
38
+ if (cases.default) return cases.default();
57
39
  }
58
40
  throw new Error("Invalid matcher or missing case");
59
41
  }
60
- global.match = match;
42
+ globalThis.match = match;
61
43
 
62
44
  exports.match = match;
63
45
  //# sourceMappingURL=match.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/helpers/match.ts"],"names":[],"mappings":"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","file":"match.cjs","sourcesContent":["import type { Option } from \"../option\";\nimport type { Result } from \"../result\";\n\n// Utility types for mixed primitive + object unions\ntype PrimitiveMembers<T> = Extract<T, PropertyKey>;\ntype ObjectKeys<T> = T extends object ? keyof T : never;\ntype ObjectPropertyType<T, K extends PropertyKey> = T extends object\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\n// Helper to determine if a key K is a primitive member or object key\ntype HandlerFor<T, K extends PropertyKey, R> = K extends PrimitiveMembers<T>\n ? () => R\n : K extends ObjectKeys<T>\n ? (value: ObjectPropertyType<T, K>) => R\n : never;\n\n// Build cases type with a single mapped type\ntype MatchCases<T, R, HasDefault extends boolean = false> = (HasDefault extends true\n ? Partial<{\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }>\n : {\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }) &\n (HasDefault extends true ? { default: () => R } : {});\n\n// Overload for Result type\nexport function match<T, E, R>(\n matcher: Result<T, E>,\n cases: {\n Ok: (value: T) => R;\n Err: (error: E) => R;\n },\n): R;\n\n// Overload for Option type\nexport function match<T, R>(\n matcher: Option<T>,\n cases: {\n Some: (value: T) => R;\n None: () => R;\n },\n): R;\n\n// Overload for mixed primitive + object unions WITH default (cases optional)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, true>,\n): R;\n\n// Overload for mixed primitive + object unions WITHOUT default (exhaustive)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, false>,\n): R;\n\n// Overload for discriminated unions with default case\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]?: (value: Extract<T, { [P in D]: K }>) => R } & {\n default: (value: T) => R;\n },\n discriminant: D,\n): R;\n\n// Overload for discriminated unions without default case (exhaustive)\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]: (value: Extract<T, { [P in D]: K }>) => R },\n discriminant: D,\n): R;\n\n// Overload for primitives with default case\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Partial<Record<T, () => R>> & { default: () => R },\n): R;\n\n// Overload for primitives without default case (exhaustive)\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Record<T, () => R>,\n): R;\n\n// Result -> Option conversion\nexport function match<T, E>(\n matcher: Result<T, E>,\n cases: {\n Ok: (value: T) => Option<T>;\n Err: (error: E) => Option<T>;\n },\n): Option<T>;\n\n// Option -> Result conversion\nexport function match<T, E>(\n matcher: Option<T>,\n cases: {\n Some: (value: T) => Result<T, E>;\n None: () => Result<T, E>;\n },\n): Result<T, E>;\n\n// Implementation\nexport function match<T, E, R>(\n matcher: Result<T, E> | Option<T> | any,\n cases: any,\n discriminant?: keyof any,\n): R {\n // Handle primitives (string, number, symbol) FIRST\n if (\n typeof matcher === \"string\" ||\n typeof matcher === \"number\" ||\n typeof matcher === \"symbol\"\n ) {\n const handler = cases[matcher];\n\n if (handler) {\n return handler();\n }\n\n if (cases.default) {\n return cases.default();\n }\n\n throw new Error(`No case found for value: ${String(matcher)}`);\n }\n\n // NEW: Handle objects with specific property keys (like { Other: [...] })\n // This must come BEFORE discriminated union check to handle mixed unions\n if (typeof matcher === \"object\" && matcher !== null && !discriminant) {\n // Check if any case key matches a property in the matcher object\n for (const key in cases) {\n if (key === \"default\") continue;\n\n if (key in matcher) {\n const handler = cases[key];\n if (handler) {\n return typeof handler === \"function\"\n ? handler(matcher[key])\n : handler();\n }\n }\n }\n\n // If no match found and there's a default, use it\n if (cases.default) {\n return cases.default();\n }\n }\n\n // Handle discriminated unions\n if (discriminant && typeof matcher === \"object\" && matcher !== null) {\n const discriminantValue = matcher[discriminant];\n const handler = cases[discriminantValue];\n\n if (handler) {\n return handler(matcher);\n }\n\n if (cases.default) {\n return cases.default(matcher);\n }\n\n throw new Error(\n `No case found for discriminant value: ${String(discriminantValue)}`,\n );\n }\n\n // Early return for Result.Ok\n if (\n typeof matcher === \"object\" &&\n matcher !== null &&\n \"isOk\" in matcher &&\n matcher.isOk()\n ) {\n if (!cases.Ok) throw new Error(\"Missing case for Ok\");\n return cases.Ok(matcher.unwrap());\n }\n\n // Early return for Result.Err\n if (\n typeof matcher === \"object\" &&\n matcher !== null &&\n \"isErr\" in matcher &&\n matcher.isErr()\n ) {\n if (!cases.Err) throw new Error(\"Missing case for Err\");\n return cases.Err(matcher.unwrapErr() as E);\n }\n\n // Early return for Option.Some\n if (\n typeof matcher === \"object\" &&\n matcher !== null &&\n \"isSome\" in matcher &&\n matcher.isSome()\n ) {\n if (!cases.Some) throw new Error(\"Missing case for Some\");\n return cases.Some(matcher.unwrap());\n }\n\n // Early return for Option.None\n if (\n typeof matcher === \"object\" &&\n matcher !== null &&\n \"isNone\" in matcher &&\n matcher.isNone()\n ) {\n if (!cases.None) throw new Error(\"Missing case for None\");\n return cases.None();\n }\n\n throw new Error(\"Invalid matcher or missing case\");\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\n(global as any).match = match;\n"]}
1
+ {"version":3,"sources":["../../src/helpers/match.ts"],"names":[],"mappings":";;;AAKA,IAAM,GAAA,GAAM,MAAO,CAAA,GAAA,CAAI,2BAA2B,CAAA;AA+F3C,SAAS,KAAA,CACd,OACA,EAAA,KAAA,EACA,YACG,EAAA;AAEH,EAAA,MAAM,IAAI,OAAO,OAAA;AACjB,EAAA,IAAI,CAAM,KAAA,QAAA,IAAY,CAAM,KAAA,QAAA,IAAY,MAAM,QAAU,EAAA;AACtD,IAAM,MAAA,OAAA,GAAU,MAAM,OAAO,CAAA;AAC7B,IAAI,IAAA,OAAA,SAAgB,OAAQ,EAAA;AAC5B,IAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,OAAQ,EAAA;AACxC,IAAA,MAAM,IAAI,KAAM,CAAA,CAAA,yBAAA,EAA4B,MAAO,CAAA,OAAO,CAAC,CAAE,CAAA,CAAA;AAAA;AAG/D,EAAI,IAAA,OAAA,KAAY,IAAQ,IAAA,CAAA,KAAM,QAAU,EAAA;AAKtC,IAAM,MAAA,GAAA,GAAM,QAAQ,GAAG,CAAA;AACvB,IAAA,IAAI,QAAQ,MAAW,EAAA;AACrB,MAAM,MAAA,OAAA,GAAU,MAAM,GAAG,CAAA;AACzB,MAAA,IAAI,CAAC,OAAS,EAAA,MAAM,IAAI,KAAM,CAAA,CAAA,iBAAA,EAAoB,GAAG,CAAE,CAAA,CAAA;AACvD,MAAI,IAAA,GAAA,KAAQ,QAAQ,GAAQ,KAAA,MAAA,SAAe,OAAQ,CAAA,OAAA,CAAQ,QAAQ,CAAA;AACnE,MAAA,IAAI,QAAQ,KAAO,EAAA,OAAO,OAAQ,CAAA,OAAA,CAAQ,WAAgB,CAAA;AAE1D,MAAA,OAAO,OAAQ,EAAA;AAAA;AAIjB,IAAA,IAAI,YAAc,EAAA;AAChB,MAAM,MAAA,EAAA,GAAK,QAAQ,YAAY,CAAA;AAC/B,MAAM,MAAA,OAAA,GAAU,MAAM,EAAE,CAAA;AACxB,MAAI,IAAA,OAAA,EAAgB,OAAA,OAAA,CAAQ,OAAO,CAAA;AACnC,MAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,QAAQ,OAAO,CAAA;AAC/C,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,sCAAA,EAAyC,MAAO,CAAA,EAAE,CAAC,CAAE,CAAA,CAAA;AAAA;AAOvE,IAAA,KAAA,MAAW,OAAO,OAAS,EAAA;AACzB,MAAA,IAAI,QAAQ,SAAW,EAAA;AACvB,MAAA,IAAI,OAAO,KAAO,EAAA;AAChB,QAAM,MAAA,OAAA,GAAU,MAAM,GAAG,CAAA;AACzB,QAAA,IAAI,OAAS,EAAA;AACX,UAAO,OAAA,OAAO,YAAY,UACtB,GAAA,OAAA,CAAQ,QAAQ,GAAG,CAAC,IACpB,OAAQ,EAAA;AAAA;AACd;AACF;AAEF,IAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,OAAQ,EAAA;AAAA;AAG1C,EAAM,MAAA,IAAI,MAAM,iCAAiC,CAAA;AACnD;AAGC,UAAA,CAAmB,KAAQ,GAAA,KAAA","file":"match.cjs","sourcesContent":["import type { Option } from \"../option\";\nimport type { Result } from \"../result\";\n\n// Hidden discriminant tag — set by Ok/Err/Some/None instances for O(1) dispatch.\n// Same Symbol as the one declared in the variant classes via Symbol.for.\nconst TAG = Symbol.for(\"@consolidados/results.tag\");\n\n// Utility types for mixed primitive + object unions\ntype PrimitiveMembers<T> = Extract<T, PropertyKey>;\ntype ObjectKeys<T> = T extends object ? keyof T : never;\ntype ObjectPropertyType<T, K extends PropertyKey> = T extends object\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\n// Helper to determine if a key K is a primitive member or object key\ntype HandlerFor<T, K extends PropertyKey, R> = K extends PrimitiveMembers<T>\n ? () => R\n : K extends ObjectKeys<T>\n ? (value: ObjectPropertyType<T, K>) => R\n : never;\n\n// Build cases type with a single mapped type\ntype MatchCases<T, R, HasDefault extends boolean = false> = (HasDefault extends true\n ? Partial<{\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }>\n : {\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }) &\n (HasDefault extends true ? { default: () => R } : {});\n\n// Overload for Result type\nexport function match<T, E, ROk, RErr>(\n matcher: Result<T, E>,\n cases: {\n Ok: (value: T) => ROk;\n Err: (error: E) => RErr;\n },\n): ROk | RErr;\n\n// Overload for Option type\nexport function match<T, RSome, RNone>(\n matcher: Option<T>,\n cases: {\n Some: (value: T) => RSome;\n None: () => RNone;\n },\n): RSome | RNone;\n\n// Overload for mixed primitive + object unions WITH default (cases optional)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, true>,\n): R;\n\n// Overload for mixed primitive + object unions WITHOUT default (exhaustive)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, false>,\n): R;\n\n// Overload for discriminated unions with default case\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]?: (value: Extract<T, { [P in D]: K }>) => R } & {\n default: (value: T) => R;\n },\n discriminant: D,\n): R;\n\n// Overload for discriminated unions without default case (exhaustive)\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]: (value: Extract<T, { [P in D]: K }>) => R },\n discriminant: D,\n): R;\n\n// Overload for primitives with default case\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Partial<Record<T, () => R>> & { default: () => R },\n): R;\n\n// Overload for primitives without default case (exhaustive)\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Record<T, () => R>,\n): R;\n\n// Implementation\nexport function match<T, E, R>(\n matcher: Result<T, E> | Option<T> | any,\n cases: any,\n discriminant?: keyof any,\n): R {\n // 1) Primitives (string/number/symbol) — direct key lookup, O(1).\n const t = typeof matcher;\n if (t === \"string\" || t === \"number\" || t === \"symbol\") {\n const handler = cases[matcher];\n if (handler) return handler();\n if (cases.default) return cases.default();\n throw new Error(`No case found for value: ${String(matcher)}`);\n }\n\n if (matcher !== null && t === \"object\") {\n // 2) Tagged variant (Ok/Err/Some/None) single Symbol read + single lookup.\n // The Symbol property is invisible to `for...in`, `Object.keys`, and\n // `JSON.stringify`, so mixed unions with plain-object variants are\n // unaffected.\n const tag = matcher[TAG];\n if (tag !== undefined) {\n const handler = cases[tag];\n if (!handler) throw new Error(`Missing case for ${tag}`);\n if (tag === \"Ok\" || tag === \"Some\") return handler(matcher.unwrap());\n if (tag === \"Err\") return handler(matcher.unwrapErr() as E);\n // tag === \"None\"\n return handler();\n }\n\n // 3) Discriminated union via explicit `discriminant` arg O(1).\n if (discriminant) {\n const dv = matcher[discriminant];\n const handler = cases[dv];\n if (handler) return handler(matcher);\n if (cases.default) return cases.default(matcher);\n throw new Error(`No case found for discriminant value: ${String(dv)}`);\n }\n\n // 4) Mixed primitive + object union iterate matcher's own enumerable\n // keys (usually 1 for tagged variant objects like `{ Other: [...] }`)\n // and look up by key in cases. This flips the loop from O(cases)\n // to O(matcher-keys), which is effectively O(1) for tagged variants.\n for (const key in matcher) {\n if (key === \"default\") continue;\n if (key in cases) {\n const handler = cases[key];\n if (handler) {\n return typeof handler === \"function\"\n ? handler(matcher[key])\n : handler();\n }\n }\n }\n if (cases.default) return cases.default();\n }\n\n throw new Error(\"Invalid matcher or missing case\");\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\n(globalThis as any).match = match;\n"]}
@@ -1,4 +1,4 @@
1
- import { R as Result, O as Option } from '../option-B_KKIecf.cjs';
1
+ import { R as Result, O as Option } from '../option-CYCiGxtw.cjs';
2
2
 
3
3
  type PrimitiveMembers<T> = Extract<T, PropertyKey>;
4
4
  type ObjectKeys<T> = T extends object ? keyof T : never;
@@ -11,14 +11,14 @@ type MatchCases<T, R, HasDefault extends boolean = false> = (HasDefault extends
11
11
  }) & (HasDefault extends true ? {
12
12
  default: () => R;
13
13
  } : {});
14
- declare function match<T, E, R>(matcher: Result<T, E>, cases: {
15
- Ok: (value: T) => R;
16
- Err: (error: E) => R;
17
- }): R;
18
- declare function match<T, R>(matcher: Option<T>, cases: {
19
- Some: (value: T) => R;
20
- None: () => R;
21
- }): R;
14
+ declare function match<T, E, ROk, RErr>(matcher: Result<T, E>, cases: {
15
+ Ok: (value: T) => ROk;
16
+ Err: (error: E) => RErr;
17
+ }): ROk | RErr;
18
+ declare function match<T, RSome, RNone>(matcher: Option<T>, cases: {
19
+ Some: (value: T) => RSome;
20
+ None: () => RNone;
21
+ }): RSome | RNone;
22
22
  declare function match<T extends PropertyKey | object, R>(matcher: T, cases: MatchCases<T, R, true>): R;
23
23
  declare function match<T extends PropertyKey | object, R>(matcher: T, cases: MatchCases<T, R, false>): R;
24
24
  declare function match<T extends {
@@ -41,13 +41,5 @@ declare function match<T extends PropertyKey, R>(matcher: T, cases: Partial<Reco
41
41
  default: () => R;
42
42
  }): R;
43
43
  declare function match<T extends PropertyKey, R>(matcher: T, cases: Record<T, () => R>): R;
44
- declare function match<T, E>(matcher: Result<T, E>, cases: {
45
- Ok: (value: T) => Option<T>;
46
- Err: (error: E) => Option<T>;
47
- }): Option<T>;
48
- declare function match<T, E>(matcher: Option<T>, cases: {
49
- Some: (value: T) => Result<T, E>;
50
- None: () => Result<T, E>;
51
- }): Result<T, E>;
52
44
 
53
45
  export { match };
@@ -1,4 +1,4 @@
1
- import { R as Result, O as Option } from '../option-B_KKIecf.js';
1
+ import { R as Result, O as Option } from '../option-CYCiGxtw.js';
2
2
 
3
3
  type PrimitiveMembers<T> = Extract<T, PropertyKey>;
4
4
  type ObjectKeys<T> = T extends object ? keyof T : never;
@@ -11,14 +11,14 @@ type MatchCases<T, R, HasDefault extends boolean = false> = (HasDefault extends
11
11
  }) & (HasDefault extends true ? {
12
12
  default: () => R;
13
13
  } : {});
14
- declare function match<T, E, R>(matcher: Result<T, E>, cases: {
15
- Ok: (value: T) => R;
16
- Err: (error: E) => R;
17
- }): R;
18
- declare function match<T, R>(matcher: Option<T>, cases: {
19
- Some: (value: T) => R;
20
- None: () => R;
21
- }): R;
14
+ declare function match<T, E, ROk, RErr>(matcher: Result<T, E>, cases: {
15
+ Ok: (value: T) => ROk;
16
+ Err: (error: E) => RErr;
17
+ }): ROk | RErr;
18
+ declare function match<T, RSome, RNone>(matcher: Option<T>, cases: {
19
+ Some: (value: T) => RSome;
20
+ None: () => RNone;
21
+ }): RSome | RNone;
22
22
  declare function match<T extends PropertyKey | object, R>(matcher: T, cases: MatchCases<T, R, true>): R;
23
23
  declare function match<T extends PropertyKey | object, R>(matcher: T, cases: MatchCases<T, R, false>): R;
24
24
  declare function match<T extends {
@@ -41,13 +41,5 @@ declare function match<T extends PropertyKey, R>(matcher: T, cases: Partial<Reco
41
41
  default: () => R;
42
42
  }): R;
43
43
  declare function match<T extends PropertyKey, R>(matcher: T, cases: Record<T, () => R>): R;
44
- declare function match<T, E>(matcher: Result<T, E>, cases: {
45
- Ok: (value: T) => Option<T>;
46
- Err: (error: E) => Option<T>;
47
- }): Option<T>;
48
- declare function match<T, E>(matcher: Option<T>, cases: {
49
- Some: (value: T) => Result<T, E>;
50
- None: () => Result<T, E>;
51
- }): Result<T, E>;
52
44
 
53
45
  export { match };
@@ -1,61 +1,43 @@
1
1
  // src/helpers/match.ts
2
+ var TAG = Symbol.for("@consolidados/results.tag");
2
3
  function match(matcher, cases, discriminant) {
3
- if (typeof matcher === "string" || typeof matcher === "number" || typeof matcher === "symbol") {
4
+ const t = typeof matcher;
5
+ if (t === "string" || t === "number" || t === "symbol") {
4
6
  const handler = cases[matcher];
5
- if (handler) {
7
+ if (handler) return handler();
8
+ if (cases.default) return cases.default();
9
+ throw new Error(`No case found for value: ${String(matcher)}`);
10
+ }
11
+ if (matcher !== null && t === "object") {
12
+ const tag = matcher[TAG];
13
+ if (tag !== void 0) {
14
+ const handler = cases[tag];
15
+ if (!handler) throw new Error(`Missing case for ${tag}`);
16
+ if (tag === "Ok" || tag === "Some") return handler(matcher.unwrap());
17
+ if (tag === "Err") return handler(matcher.unwrapErr());
6
18
  return handler();
7
19
  }
8
- if (cases.default) {
9
- return cases.default();
20
+ if (discriminant) {
21
+ const dv = matcher[discriminant];
22
+ const handler = cases[dv];
23
+ if (handler) return handler(matcher);
24
+ if (cases.default) return cases.default(matcher);
25
+ throw new Error(`No case found for discriminant value: ${String(dv)}`);
10
26
  }
11
- throw new Error(`No case found for value: ${String(matcher)}`);
12
- }
13
- if (typeof matcher === "object" && matcher !== null && !discriminant) {
14
- for (const key in cases) {
27
+ for (const key in matcher) {
15
28
  if (key === "default") continue;
16
- if (key in matcher) {
29
+ if (key in cases) {
17
30
  const handler = cases[key];
18
31
  if (handler) {
19
32
  return typeof handler === "function" ? handler(matcher[key]) : handler();
20
33
  }
21
34
  }
22
35
  }
23
- if (cases.default) {
24
- return cases.default();
25
- }
26
- }
27
- if (discriminant && typeof matcher === "object" && matcher !== null) {
28
- const discriminantValue = matcher[discriminant];
29
- const handler = cases[discriminantValue];
30
- if (handler) {
31
- return handler(matcher);
32
- }
33
- if (cases.default) {
34
- return cases.default(matcher);
35
- }
36
- throw new Error(
37
- `No case found for discriminant value: ${String(discriminantValue)}`
38
- );
39
- }
40
- if (typeof matcher === "object" && matcher !== null && "isOk" in matcher && matcher.isOk()) {
41
- if (!cases.Ok) throw new Error("Missing case for Ok");
42
- return cases.Ok(matcher.unwrap());
43
- }
44
- if (typeof matcher === "object" && matcher !== null && "isErr" in matcher && matcher.isErr()) {
45
- if (!cases.Err) throw new Error("Missing case for Err");
46
- return cases.Err(matcher.unwrapErr());
47
- }
48
- if (typeof matcher === "object" && matcher !== null && "isSome" in matcher && matcher.isSome()) {
49
- if (!cases.Some) throw new Error("Missing case for Some");
50
- return cases.Some(matcher.unwrap());
51
- }
52
- if (typeof matcher === "object" && matcher !== null && "isNone" in matcher && matcher.isNone()) {
53
- if (!cases.None) throw new Error("Missing case for None");
54
- return cases.None();
36
+ if (cases.default) return cases.default();
55
37
  }
56
38
  throw new Error("Invalid matcher or missing case");
57
39
  }
58
- global.match = match;
40
+ globalThis.match = match;
59
41
 
60
42
  export { match };
61
43
  //# sourceMappingURL=match.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/helpers/match.ts"],"names":[],"mappings":"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","file":"match.js","sourcesContent":["import type { Option } from \"../option\";\nimport type { Result } from \"../result\";\n\n// Utility types for mixed primitive + object unions\ntype PrimitiveMembers<T> = Extract<T, PropertyKey>;\ntype ObjectKeys<T> = T extends object ? keyof T : never;\ntype ObjectPropertyType<T, K extends PropertyKey> = T extends object\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\n// Helper to determine if a key K is a primitive member or object key\ntype HandlerFor<T, K extends PropertyKey, R> = K extends PrimitiveMembers<T>\n ? () => R\n : K extends ObjectKeys<T>\n ? (value: ObjectPropertyType<T, K>) => R\n : never;\n\n// Build cases type with a single mapped type\ntype MatchCases<T, R, HasDefault extends boolean = false> = (HasDefault extends true\n ? Partial<{\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }>\n : {\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }) &\n (HasDefault extends true ? { default: () => R } : {});\n\n// Overload for Result type\nexport function match<T, E, R>(\n matcher: Result<T, E>,\n cases: {\n Ok: (value: T) => R;\n Err: (error: E) => R;\n },\n): R;\n\n// Overload for Option type\nexport function match<T, R>(\n matcher: Option<T>,\n cases: {\n Some: (value: T) => R;\n None: () => R;\n },\n): R;\n\n// Overload for mixed primitive + object unions WITH default (cases optional)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, true>,\n): R;\n\n// Overload for mixed primitive + object unions WITHOUT default (exhaustive)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, false>,\n): R;\n\n// Overload for discriminated unions with default case\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]?: (value: Extract<T, { [P in D]: K }>) => R } & {\n default: (value: T) => R;\n },\n discriminant: D,\n): R;\n\n// Overload for discriminated unions without default case (exhaustive)\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]: (value: Extract<T, { [P in D]: K }>) => R },\n discriminant: D,\n): R;\n\n// Overload for primitives with default case\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Partial<Record<T, () => R>> & { default: () => R },\n): R;\n\n// Overload for primitives without default case (exhaustive)\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Record<T, () => R>,\n): R;\n\n// Result -> Option conversion\nexport function match<T, E>(\n matcher: Result<T, E>,\n cases: {\n Ok: (value: T) => Option<T>;\n Err: (error: E) => Option<T>;\n },\n): Option<T>;\n\n// Option -> Result conversion\nexport function match<T, E>(\n matcher: Option<T>,\n cases: {\n Some: (value: T) => Result<T, E>;\n None: () => Result<T, E>;\n },\n): Result<T, E>;\n\n// Implementation\nexport function match<T, E, R>(\n matcher: Result<T, E> | Option<T> | any,\n cases: any,\n discriminant?: keyof any,\n): R {\n // Handle primitives (string, number, symbol) FIRST\n if (\n typeof matcher === \"string\" ||\n typeof matcher === \"number\" ||\n typeof matcher === \"symbol\"\n ) {\n const handler = cases[matcher];\n\n if (handler) {\n return handler();\n }\n\n if (cases.default) {\n return cases.default();\n }\n\n throw new Error(`No case found for value: ${String(matcher)}`);\n }\n\n // NEW: Handle objects with specific property keys (like { Other: [...] })\n // This must come BEFORE discriminated union check to handle mixed unions\n if (typeof matcher === \"object\" && matcher !== null && !discriminant) {\n // Check if any case key matches a property in the matcher object\n for (const key in cases) {\n if (key === \"default\") continue;\n\n if (key in matcher) {\n const handler = cases[key];\n if (handler) {\n return typeof handler === \"function\"\n ? handler(matcher[key])\n : handler();\n }\n }\n }\n\n // If no match found and there's a default, use it\n if (cases.default) {\n return cases.default();\n }\n }\n\n // Handle discriminated unions\n if (discriminant && typeof matcher === \"object\" && matcher !== null) {\n const discriminantValue = matcher[discriminant];\n const handler = cases[discriminantValue];\n\n if (handler) {\n return handler(matcher);\n }\n\n if (cases.default) {\n return cases.default(matcher);\n }\n\n throw new Error(\n `No case found for discriminant value: ${String(discriminantValue)}`,\n );\n }\n\n // Early return for Result.Ok\n if (\n typeof matcher === \"object\" &&\n matcher !== null &&\n \"isOk\" in matcher &&\n matcher.isOk()\n ) {\n if (!cases.Ok) throw new Error(\"Missing case for Ok\");\n return cases.Ok(matcher.unwrap());\n }\n\n // Early return for Result.Err\n if (\n typeof matcher === \"object\" &&\n matcher !== null &&\n \"isErr\" in matcher &&\n matcher.isErr()\n ) {\n if (!cases.Err) throw new Error(\"Missing case for Err\");\n return cases.Err(matcher.unwrapErr() as E);\n }\n\n // Early return for Option.Some\n if (\n typeof matcher === \"object\" &&\n matcher !== null &&\n \"isSome\" in matcher &&\n matcher.isSome()\n ) {\n if (!cases.Some) throw new Error(\"Missing case for Some\");\n return cases.Some(matcher.unwrap());\n }\n\n // Early return for Option.None\n if (\n typeof matcher === \"object\" &&\n matcher !== null &&\n \"isNone\" in matcher &&\n matcher.isNone()\n ) {\n if (!cases.None) throw new Error(\"Missing case for None\");\n return cases.None();\n }\n\n throw new Error(\"Invalid matcher or missing case\");\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\n(global as any).match = match;\n"]}
1
+ {"version":3,"sources":["../../src/helpers/match.ts"],"names":[],"mappings":";AAKA,IAAM,GAAA,GAAM,MAAO,CAAA,GAAA,CAAI,2BAA2B,CAAA;AA+F3C,SAAS,KAAA,CACd,OACA,EAAA,KAAA,EACA,YACG,EAAA;AAEH,EAAA,MAAM,IAAI,OAAO,OAAA;AACjB,EAAA,IAAI,CAAM,KAAA,QAAA,IAAY,CAAM,KAAA,QAAA,IAAY,MAAM,QAAU,EAAA;AACtD,IAAM,MAAA,OAAA,GAAU,MAAM,OAAO,CAAA;AAC7B,IAAI,IAAA,OAAA,SAAgB,OAAQ,EAAA;AAC5B,IAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,OAAQ,EAAA;AACxC,IAAA,MAAM,IAAI,KAAM,CAAA,CAAA,yBAAA,EAA4B,MAAO,CAAA,OAAO,CAAC,CAAE,CAAA,CAAA;AAAA;AAG/D,EAAI,IAAA,OAAA,KAAY,IAAQ,IAAA,CAAA,KAAM,QAAU,EAAA;AAKtC,IAAM,MAAA,GAAA,GAAM,QAAQ,GAAG,CAAA;AACvB,IAAA,IAAI,QAAQ,MAAW,EAAA;AACrB,MAAM,MAAA,OAAA,GAAU,MAAM,GAAG,CAAA;AACzB,MAAA,IAAI,CAAC,OAAS,EAAA,MAAM,IAAI,KAAM,CAAA,CAAA,iBAAA,EAAoB,GAAG,CAAE,CAAA,CAAA;AACvD,MAAI,IAAA,GAAA,KAAQ,QAAQ,GAAQ,KAAA,MAAA,SAAe,OAAQ,CAAA,OAAA,CAAQ,QAAQ,CAAA;AACnE,MAAA,IAAI,QAAQ,KAAO,EAAA,OAAO,OAAQ,CAAA,OAAA,CAAQ,WAAgB,CAAA;AAE1D,MAAA,OAAO,OAAQ,EAAA;AAAA;AAIjB,IAAA,IAAI,YAAc,EAAA;AAChB,MAAM,MAAA,EAAA,GAAK,QAAQ,YAAY,CAAA;AAC/B,MAAM,MAAA,OAAA,GAAU,MAAM,EAAE,CAAA;AACxB,MAAI,IAAA,OAAA,EAAgB,OAAA,OAAA,CAAQ,OAAO,CAAA;AACnC,MAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,QAAQ,OAAO,CAAA;AAC/C,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,sCAAA,EAAyC,MAAO,CAAA,EAAE,CAAC,CAAE,CAAA,CAAA;AAAA;AAOvE,IAAA,KAAA,MAAW,OAAO,OAAS,EAAA;AACzB,MAAA,IAAI,QAAQ,SAAW,EAAA;AACvB,MAAA,IAAI,OAAO,KAAO,EAAA;AAChB,QAAM,MAAA,OAAA,GAAU,MAAM,GAAG,CAAA;AACzB,QAAA,IAAI,OAAS,EAAA;AACX,UAAO,OAAA,OAAO,YAAY,UACtB,GAAA,OAAA,CAAQ,QAAQ,GAAG,CAAC,IACpB,OAAQ,EAAA;AAAA;AACd;AACF;AAEF,IAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,OAAQ,EAAA;AAAA;AAG1C,EAAM,MAAA,IAAI,MAAM,iCAAiC,CAAA;AACnD;AAGC,UAAA,CAAmB,KAAQ,GAAA,KAAA","file":"match.js","sourcesContent":["import type { Option } from \"../option\";\nimport type { Result } from \"../result\";\n\n// Hidden discriminant tag — set by Ok/Err/Some/None instances for O(1) dispatch.\n// Same Symbol as the one declared in the variant classes via Symbol.for.\nconst TAG = Symbol.for(\"@consolidados/results.tag\");\n\n// Utility types for mixed primitive + object unions\ntype PrimitiveMembers<T> = Extract<T, PropertyKey>;\ntype ObjectKeys<T> = T extends object ? keyof T : never;\ntype ObjectPropertyType<T, K extends PropertyKey> = T extends object\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\n// Helper to determine if a key K is a primitive member or object key\ntype HandlerFor<T, K extends PropertyKey, R> = K extends PrimitiveMembers<T>\n ? () => R\n : K extends ObjectKeys<T>\n ? (value: ObjectPropertyType<T, K>) => R\n : never;\n\n// Build cases type with a single mapped type\ntype MatchCases<T, R, HasDefault extends boolean = false> = (HasDefault extends true\n ? Partial<{\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }>\n : {\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }) &\n (HasDefault extends true ? { default: () => R } : {});\n\n// Overload for Result type\nexport function match<T, E, ROk, RErr>(\n matcher: Result<T, E>,\n cases: {\n Ok: (value: T) => ROk;\n Err: (error: E) => RErr;\n },\n): ROk | RErr;\n\n// Overload for Option type\nexport function match<T, RSome, RNone>(\n matcher: Option<T>,\n cases: {\n Some: (value: T) => RSome;\n None: () => RNone;\n },\n): RSome | RNone;\n\n// Overload for mixed primitive + object unions WITH default (cases optional)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, true>,\n): R;\n\n// Overload for mixed primitive + object unions WITHOUT default (exhaustive)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, false>,\n): R;\n\n// Overload for discriminated unions with default case\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]?: (value: Extract<T, { [P in D]: K }>) => R } & {\n default: (value: T) => R;\n },\n discriminant: D,\n): R;\n\n// Overload for discriminated unions without default case (exhaustive)\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]: (value: Extract<T, { [P in D]: K }>) => R },\n discriminant: D,\n): R;\n\n// Overload for primitives with default case\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Partial<Record<T, () => R>> & { default: () => R },\n): R;\n\n// Overload for primitives without default case (exhaustive)\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Record<T, () => R>,\n): R;\n\n// Implementation\nexport function match<T, E, R>(\n matcher: Result<T, E> | Option<T> | any,\n cases: any,\n discriminant?: keyof any,\n): R {\n // 1) Primitives (string/number/symbol) — direct key lookup, O(1).\n const t = typeof matcher;\n if (t === \"string\" || t === \"number\" || t === \"symbol\") {\n const handler = cases[matcher];\n if (handler) return handler();\n if (cases.default) return cases.default();\n throw new Error(`No case found for value: ${String(matcher)}`);\n }\n\n if (matcher !== null && t === \"object\") {\n // 2) Tagged variant (Ok/Err/Some/None) single Symbol read + single lookup.\n // The Symbol property is invisible to `for...in`, `Object.keys`, and\n // `JSON.stringify`, so mixed unions with plain-object variants are\n // unaffected.\n const tag = matcher[TAG];\n if (tag !== undefined) {\n const handler = cases[tag];\n if (!handler) throw new Error(`Missing case for ${tag}`);\n if (tag === \"Ok\" || tag === \"Some\") return handler(matcher.unwrap());\n if (tag === \"Err\") return handler(matcher.unwrapErr() as E);\n // tag === \"None\"\n return handler();\n }\n\n // 3) Discriminated union via explicit `discriminant` arg O(1).\n if (discriminant) {\n const dv = matcher[discriminant];\n const handler = cases[dv];\n if (handler) return handler(matcher);\n if (cases.default) return cases.default(matcher);\n throw new Error(`No case found for discriminant value: ${String(dv)}`);\n }\n\n // 4) Mixed primitive + object union iterate matcher's own enumerable\n // keys (usually 1 for tagged variant objects like `{ Other: [...] }`)\n // and look up by key in cases. This flips the loop from O(cases)\n // to O(matcher-keys), which is effectively O(1) for tagged variants.\n for (const key in matcher) {\n if (key === \"default\") continue;\n if (key in cases) {\n const handler = cases[key];\n if (handler) {\n return typeof handler === \"function\"\n ? handler(matcher[key])\n : handler();\n }\n }\n }\n if (cases.default) return cases.default();\n }\n\n throw new Error(\"Invalid matcher or missing case\");\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\n(globalThis as any).match = match;\n"]}