fix(patterns): preserve literal inference in compound matchers - #3335
Open
kriskowal wants to merge 1 commit into
Open
fix(patterns): preserve literal inference in compound matchers#3335kriskowal wants to merge 1 commit into
kriskowal wants to merge 1 commit into
Conversation
Pattern combinators previously inferred their generic arguments through broad Pattern arrays and CopyRecord constraints. TypeScript therefore widened object literal discriminants before TypeFromPattern could inspect them, which propagated broad method parameters through interface guards and makeExo. Use const type parameters for M.or, M.and, M.splitArray, and M.splitRecord, including their optional and rest pattern parameters, so literal unions, record fields, and tuples survive inference. TypeFromPattern removes only the readonly modifier introduced by const object inference when producing matched record values, preserving the existing mutable public result shape. CastedPattern<T> remains useful for unverifiable branded or cross-field claims, but it is an unchecked escape hatch rather than the remedy for literals that the API can preserve soundly. The focused type regressions cover raw literal unions, discriminants in splitRecord, literal tuples and rest patterns in splitArray, intersections through M.and, and a nested interface method guard. The change is declaration-only and does not alter runtime matching or compatibility for callers that do not rely on widened inferred types.
|
kriscendobot
added a commit
to kriscendobot/garden
that referenced
this pull request
Jul 30, 2026
…n endolin-garden-ece02cb4
gibson042
approved these changes
Jul 31, 2026
Comment on lines
+63
to
+66
| ? // Const type parameters preserve object literals as readonly, but | ||
| // TypeFromPattern describes matched values using the existing mutable | ||
| // record shape. | ||
| Simplify<{ -readonly [K in keyof P]: TypeFromPattern<P[K]> }> |
Member
There was a problem hiding this comment.
Endo patterns only apply to immutable data; shouldn't this force readonly?
Suggested change
| ? // Const type parameters preserve object literals as readonly, but | |
| // TypeFromPattern describes matched values using the existing mutable | |
| // record shape. | |
| Simplify<{ -readonly [K in keyof P]: TypeFromPattern<P[K]> }> | |
| ? // An immutable CopyRecord can be described by a mutable template. | |
| Simplify<{ readonly [K in keyof P]: TypeFromPattern<P[K]> }> |
| type TFSplitRecord<Req, Opt, Rest = never> = Simplify< | ||
| (Req extends CopyRecord<any> | ||
| ? { [K in keyof Req]: TypeFromPattern<Req[K]> } | ||
| ? { -readonly [K in keyof Req]: TypeFromPattern<Req[K]> } |
Member
There was a problem hiding this comment.
Suggested change
| ? { -readonly [K in keyof Req]: TypeFromPattern<Req[K]> } | |
| ? { readonly [K in keyof Req]: TypeFromPattern<Req[K]> } |
| : {}) & | ||
| (Opt extends CopyRecord<any> | ||
| ? { [K in keyof Opt]?: TypeFromPattern<Opt[K]> } | ||
| ? { -readonly [K in keyof Opt]?: TypeFromPattern<Opt[K]> } |
Member
There was a problem hiding this comment.
Suggested change
| ? { -readonly [K in keyof Opt]?: TypeFromPattern<Opt[K]> } | |
| ? { readonly [K in keyof Opt]?: TypeFromPattern<Opt[K]> } |
Comment on lines
+241
to
+242
| * Const type parameters preserve object literals as readonly, but matched | ||
| * record values retain the existing mutable shape. |
Member
There was a problem hiding this comment.
Suggested change
| * Const type parameters preserve object literals as readonly, but matched | |
| * record values retain the existing mutable shape. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The
@endo/patternsmatcher declarations preserve literal discriminants and tuple shapes throughM.or,M.and,M.splitArray, andM.splitRecord. This keepsTypeFromPatternand interface method-guard inference narrow enough for implementations that use discriminated inputs.The declarations cover required, optional, and rest pattern positions. Const type parameters retain literal information at the generic boundary, while type inference removes only the readonly modifier introduced for object literals so matched records keep their existing mutable public shape.
CastedPattern<T>remains available for unverifiable branded or cross-field claims, but is no longer needed for literals the reusable API can preserve soundly.Security Considerations
This declaration-only change introduces no new authority or security boundary and does not alter runtime matching.
Scaling Considerations
This change does not affect runtime CPU, memory, storage, or message use.
Documentation Considerations
The narrower inferred types are backward compatible for callers that do not rely on widened inference. No documentation or upgrade action is required.
Testing Considerations
Type regressions cover literal unions, record discriminants, tuple and rest patterns, intersections, and a nested interface method guard. The
@endo/patternspackage lint passes.Compatibility Considerations
Existing runtime behavior and mutable matched-record result shapes remain unchanged. TypeScript consumers gain narrower, more accurate inference for compound literal patterns.
Upgrade Considerations
No live-system upgrade considerations apply.