Infer a literal fixedSize for struct codecs - #1761
Conversation
🦋 Changeset detectedLatest commit: 76328e8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 47 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
BundleMonFiles updated (4)
Unchanged files (143)
Total files change -713B -0.13% Final result: ✅ View report in BundleMon website ➡️ |
|
Hey @mcintyre94, this one is green and ready whenever you get a chance. I left a couple of open questions in the description (the 512 cap, and whether the size helpers should stay local or move into codecs-core for the union / predicate / pattern-match work) and I'm happy to go whichever way you prefer. No rush! |
|
@plutohan Thanks for this, and sorry I didn't get back to you quicker. Part of the reason I opened this as an issue is because I think there's some research/feasibility/stress testing to do before committing to a solution here. I appreciate your PR as a demonstration of how the implementation will look if we land it, but I'm a bit unsure about committing to this Typescript complexity. We need to think a bit more about the cost/benefit here - I do think there's a real benefit for small structs and unions/predicates. I've marked this do-not-close for now so it won't get closed before we make a decision. WRT to your open questions, I think just having it in struct for now and a patch changeset are right, so no immediate changes. I think the approach is good too, it's just a decision of whether it's worth it. |
|
Thanks @mcintyre94, no worries on the timing, and totally fair to weigh the complexity. On the cost side: the type machinery is self-contained in struct.ts (about 40 lines) and the cap is the safety net. Because it is gated at 512 bytes and the range check walks a fixed tuple rather than building one from the field size, it can never produce a TS2589 in a consumer's build. Anything over the cap, or any non-literal field, just stays On the benefit: it is mainly the unions / predicates / pattern-match work (#1443, #1683) being able to tell struct branches of different sizes apart instead of widening, plus the v1 tx config case. Happy to help with the stress testing you mentioned if useful, for example running it across the real struct codecs in the repo and checking the tsc compile-time impact. No rush either way, and feel free to park it. |
Closes #1738.
Made
getStructEncoder/Decoder/Codecinfer a literalfixedSizefrom their fields instead of just falling back tonumber:So the size-aware combinators (
getUnion*,getPredicate*,getPatternMatch*) can actually tell struct branches of different sizes apart now, which was the point in the issue.How it works: it's just a type-level sum of each field's
fixedSize. The catch is the addition builds a tuple of that length, and TS gives up with TS2589 once a tuple gets near ~1000 elements. So to make sure this never blows up in someone's code, I capped it (MaxInferredStructSize, 512 for now) — within the cap you get the literal sum, anything bigger or a non-literal field just staysnumberlike before. The in-range check walks the cap tuple down instead of building a tuple of the field's size, so a huge single field doesn't trip TS2589 either.Runtime is untouched — it already summed the sizes, this is purely the types.
Verified with
test:typecheck(the acceptance criterion from the issue is in there as a typetest), plus lint/prettier and the unit tests on node + browser.Couple of things I wasn't sure about:
struct.ts, or moved intocodecs-coreso the union/predicate/pattern-match work (Incorrect type overloads for predicate/pattern match codecs #1443, fix: align codec branch size types #1683) can reuse them?FixedSizeEncoder<T>tests.