unthrown 5.11.0 → 5.12.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/dist/index.d.cts +30 -2
- package/dist/index.d.mts +30 -2
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -63,6 +63,32 @@ type UniversalPattern = PatternMatcher<unknown> & {
|
|
|
63
63
|
* @internal
|
|
64
64
|
*/
|
|
65
65
|
type MatchedOf<Pt> = Pt extends PatternMatcher<infer M> ? M : Pt extends object ? { [K in keyof Pt]: MatchedOf<Pt[K]>; } : Pt;
|
|
66
|
+
/** Whether a value's type describes multiple alternatives, not one literal. */
|
|
67
|
+
type IsUnion<T, Whole = T> = T extends Whole ? ([Whole] extends [T] ? false : true) : never;
|
|
68
|
+
/**
|
|
69
|
+
* What a pattern is guaranteed to cover, rather than merely able to match.
|
|
70
|
+
*
|
|
71
|
+
* A value pattern is an equality test, so it discharges a case only when its
|
|
72
|
+
* type is a **unit type** — one inhabitant: a string / number / bigint /
|
|
73
|
+
* boolean literal, `null`, `undefined`, a `unique symbol` — or a plain object
|
|
74
|
+
* of such fields, recursively (so a variable inferred as `{ _tag: string }`
|
|
75
|
+
* cannot make an entire tagged union exhaustive). Everything else covers
|
|
76
|
+
* nothing: a widened `string`, a template literal (`` `E_${string}` `` is as
|
|
77
|
+
* wide as `string`), a union (one runtime value however many alternatives its
|
|
78
|
+
* type lists — a union of `P.*` patterns included, which is why the union test
|
|
79
|
+
* runs before the predicate one), an array or a function (compared by identity
|
|
80
|
+
* at runtime). Keep `MatchedOf` for handler narrowing; subtract only this
|
|
81
|
+
* coverage. Branded predicate patterns still cover their declared type: unlike
|
|
82
|
+
* a value, they test the whole type. An allow-list rather than a deny-list of
|
|
83
|
+
* wide types, so a shape it did not anticipate fails closed. One gap is
|
|
84
|
+
* accepted: a class instance is structurally an object type, so it recurses
|
|
85
|
+
* like a plain object while the runtime compares it by identity — pinned in
|
|
86
|
+
* `types.test-d.ts`.
|
|
87
|
+
*
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
type CoveredBy<Pt> = true extends IsUnion<Pt> ? never : [Pt] extends [PatternMatcher<infer M>] ? M : Pt extends string ? {} extends Record<Pt, never> ? never : Pt : Pt extends number ? number extends Pt ? never : Pt : Pt extends bigint ? bigint extends Pt ? never : Pt : Pt extends symbol ? symbol extends Pt ? never : Pt : Pt extends boolean | null | undefined ? Pt : Pt extends readonly unknown[] | ((...args: never) => unknown) ? never : Pt extends object ? { [K in keyof Pt]: CoveredBy<Pt[K]>; } : never;
|
|
91
|
+
type CoveredByPatterns<Pts extends readonly unknown[]> = { [I in keyof Pts]: CoveredBy<Pts[I]>; }[number];
|
|
66
92
|
/**
|
|
67
93
|
* Reject a **keyless object pattern** (`{}`) where it is written.
|
|
68
94
|
*
|
|
@@ -173,9 +199,11 @@ type Matcher<E, Remaining, O, Declared = Unset> = {
|
|
|
173
199
|
* patterns — `matcher.with(P.tag("A"), P.tag("B"), handler)`). The handler
|
|
174
200
|
* receives the input narrowed to what the patterns match (computed against
|
|
175
201
|
* `Remaining`, so cases already handled by earlier arms are excluded); the
|
|
176
|
-
*
|
|
202
|
+
* guaranteed covered cases are subtracted from `Remaining`. A widened value
|
|
203
|
+
* pattern (e.g. `{ _tag: string }`) can match but proves no coverage: use
|
|
204
|
+
* literal patterns / `P.tag` to discharge the remaining cases.
|
|
177
205
|
*/
|
|
178
|
-
with<const Pts extends readonly [unknown, ...unknown[]], O2>(...args: [...patterns: { [I in keyof Pts]: NoEmptyPattern<Pts[I]>; }, handler: (value: Extract<Remaining, MatchedOf<Pts[number]>>) => BranchReturn<Declared, O2>]): Matcher<E, Exclude<Remaining,
|
|
206
|
+
with<const Pts extends readonly [unknown, ...unknown[]], O2>(...args: [...patterns: { [I in keyof Pts]: NoEmptyPattern<Pts[I]>; }, handler: (value: Extract<Remaining, MatchedOf<Pts[number]>>) => BranchReturn<Declared, O2>]): Matcher<E, Exclude<Remaining, CoveredByPatterns<Pts>>, O | O2, Declared>;
|
|
179
207
|
/**
|
|
180
208
|
* Declare the match's output type up front: every subsequent branch handler
|
|
181
209
|
* is checked against `R`, and the match evaluates to `R` instead of the
|
package/dist/index.d.mts
CHANGED
|
@@ -63,6 +63,32 @@ type UniversalPattern = PatternMatcher<unknown> & {
|
|
|
63
63
|
* @internal
|
|
64
64
|
*/
|
|
65
65
|
type MatchedOf<Pt> = Pt extends PatternMatcher<infer M> ? M : Pt extends object ? { [K in keyof Pt]: MatchedOf<Pt[K]>; } : Pt;
|
|
66
|
+
/** Whether a value's type describes multiple alternatives, not one literal. */
|
|
67
|
+
type IsUnion<T, Whole = T> = T extends Whole ? ([Whole] extends [T] ? false : true) : never;
|
|
68
|
+
/**
|
|
69
|
+
* What a pattern is guaranteed to cover, rather than merely able to match.
|
|
70
|
+
*
|
|
71
|
+
* A value pattern is an equality test, so it discharges a case only when its
|
|
72
|
+
* type is a **unit type** — one inhabitant: a string / number / bigint /
|
|
73
|
+
* boolean literal, `null`, `undefined`, a `unique symbol` — or a plain object
|
|
74
|
+
* of such fields, recursively (so a variable inferred as `{ _tag: string }`
|
|
75
|
+
* cannot make an entire tagged union exhaustive). Everything else covers
|
|
76
|
+
* nothing: a widened `string`, a template literal (`` `E_${string}` `` is as
|
|
77
|
+
* wide as `string`), a union (one runtime value however many alternatives its
|
|
78
|
+
* type lists — a union of `P.*` patterns included, which is why the union test
|
|
79
|
+
* runs before the predicate one), an array or a function (compared by identity
|
|
80
|
+
* at runtime). Keep `MatchedOf` for handler narrowing; subtract only this
|
|
81
|
+
* coverage. Branded predicate patterns still cover their declared type: unlike
|
|
82
|
+
* a value, they test the whole type. An allow-list rather than a deny-list of
|
|
83
|
+
* wide types, so a shape it did not anticipate fails closed. One gap is
|
|
84
|
+
* accepted: a class instance is structurally an object type, so it recurses
|
|
85
|
+
* like a plain object while the runtime compares it by identity — pinned in
|
|
86
|
+
* `types.test-d.ts`.
|
|
87
|
+
*
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
type CoveredBy<Pt> = true extends IsUnion<Pt> ? never : [Pt] extends [PatternMatcher<infer M>] ? M : Pt extends string ? {} extends Record<Pt, never> ? never : Pt : Pt extends number ? number extends Pt ? never : Pt : Pt extends bigint ? bigint extends Pt ? never : Pt : Pt extends symbol ? symbol extends Pt ? never : Pt : Pt extends boolean | null | undefined ? Pt : Pt extends readonly unknown[] | ((...args: never) => unknown) ? never : Pt extends object ? { [K in keyof Pt]: CoveredBy<Pt[K]>; } : never;
|
|
91
|
+
type CoveredByPatterns<Pts extends readonly unknown[]> = { [I in keyof Pts]: CoveredBy<Pts[I]>; }[number];
|
|
66
92
|
/**
|
|
67
93
|
* Reject a **keyless object pattern** (`{}`) where it is written.
|
|
68
94
|
*
|
|
@@ -173,9 +199,11 @@ type Matcher<E, Remaining, O, Declared = Unset> = {
|
|
|
173
199
|
* patterns — `matcher.with(P.tag("A"), P.tag("B"), handler)`). The handler
|
|
174
200
|
* receives the input narrowed to what the patterns match (computed against
|
|
175
201
|
* `Remaining`, so cases already handled by earlier arms are excluded); the
|
|
176
|
-
*
|
|
202
|
+
* guaranteed covered cases are subtracted from `Remaining`. A widened value
|
|
203
|
+
* pattern (e.g. `{ _tag: string }`) can match but proves no coverage: use
|
|
204
|
+
* literal patterns / `P.tag` to discharge the remaining cases.
|
|
177
205
|
*/
|
|
178
|
-
with<const Pts extends readonly [unknown, ...unknown[]], O2>(...args: [...patterns: { [I in keyof Pts]: NoEmptyPattern<Pts[I]>; }, handler: (value: Extract<Remaining, MatchedOf<Pts[number]>>) => BranchReturn<Declared, O2>]): Matcher<E, Exclude<Remaining,
|
|
206
|
+
with<const Pts extends readonly [unknown, ...unknown[]], O2>(...args: [...patterns: { [I in keyof Pts]: NoEmptyPattern<Pts[I]>; }, handler: (value: Extract<Remaining, MatchedOf<Pts[number]>>) => BranchReturn<Declared, O2>]): Matcher<E, Exclude<Remaining, CoveredByPatterns<Pts>>, O | O2, Declared>;
|
|
179
207
|
/**
|
|
180
208
|
* Declare the match's output type up front: every subsequent branch handler
|
|
181
209
|
* is checked against `R`, and the match evaluates to `R` instead of the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unthrown",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.12.0",
|
|
4
4
|
"description": "Explicit errors as values, with a separate defect (panic) channel",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"defect",
|
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@btravstack/tsconfig": "0.4.0",
|
|
50
|
-
"@types/node": "26.6.
|
|
51
|
-
"@vitest/coverage-v8": "5.0.
|
|
50
|
+
"@types/node": "26.6.3",
|
|
51
|
+
"@vitest/coverage-v8": "5.0.2",
|
|
52
52
|
"tsdown": "0.23.0",
|
|
53
53
|
"typescript": "7.0.2",
|
|
54
|
-
"vitest": "5.0.
|
|
54
|
+
"vitest": "5.0.2"
|
|
55
55
|
},
|
|
56
56
|
"engines": {
|
|
57
57
|
"node": ">=20"
|