🔀 Merge chore/open-universe-guidance into main

This commit is contained in:
tmu committed 2026-09-23 20:01:52 +00:00
commit 2c856f28e3
2 files changed
+16 -1

No files matched your search

+13
View File
@@ -40,6 +40,19 @@ Yet to be implemented
- **`NaN` and `-0` cannot be matched specifically.** They have no literal type, - **`NaN` and `-0` cannot be matched specifically.** They have no literal type,
so both stay part of `number`. so both stay part of `number`.
### Why open universes are rejected
An open universe — one carrying a broad member, as in
`type Units = "s" | "ms" | "min" | (string & {})` — is not a dispatch concern.
If the values arrive from outside the program, parse them at the boundary down
to a finite union and match the narrowed result; the openness never reaches the
matcher. If the domain is genuinely extensible, the right shape is a runtime
`Map` of handlers, where "no handler" is a lookup, not a pattern. Either way an
open matcher would abandon the one guarantee this library exists to give —
provable exhaustiveness — to automate what a `switch` and a default arm already
cover. The type-level cost of supporting open universes is recorded in
[development/library.md](./development/library.md#supported-universes).
## License ## License
MIT © 2025 tmu. See [LICENSE](./LICENSE). MIT © 2025 tmu. See [LICENSE](./LICENSE).
+3 -1
View File
@@ -167,7 +167,9 @@ Extract<T, Stringified<T>>` catches numeric collisions too.
non-self-referential parameter type (`{ [K in keyof H]: … R … }` gives non-self-referential parameter type (`{ [K in keyof H]: … R … }` gives
`unknown`); an F-bounded guard referencing `keyof Handled` in `Handled`'s own `unknown`); an F-bounded guard referencing `keyof Handled` in `Handled`'s own
constraint sees the constraint, not the map; all handlers share one `R` (only constraint sees the constraint, not the map; all handlers share one `R` (only
the fallback widens it); `IsLiteral` is the finite-literal predicate. the fallback widens it); `IsLiteral` is the finite-literal predicate. The
user-facing consequence — open universes are a parsing or registry concern,
not a dispatch one — is guidance in README § Why open universes are rejected.
- **`Member<T, K>` without the gate:** sound, but a colliding handler gets a - **`Member<T, K>` without the gate:** sound, but a colliding handler gets a
union and `1 | "1"` stays one runtime key. union and `1 | "1"` stays one runtime key.
- **A round-trip injectivity gate** (`IsEqual<T, PatternParam<PatternKey<T>>>`): - **A round-trip injectivity gate** (`IsEqual<T, PatternParam<PatternKey<T>>>`):