fix(connect): split mapStateToProps/mapDispatchToProps unions into ordered overloads (#2244)#2340
Open
veksa wants to merge 1 commit into
Open
fix(connect): split mapStateToProps/mapDispatchToProps unions into ordered overloads (#2244)#2340veksa wants to merge 1 commit into
connect): split mapStateToProps/mapDispatchToProps unions into ordered overloads (#2244)#2340veksa wants to merge 1 commit into
Conversation
…nto ordered overloads (reduxjs#2244)
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.
Fixes #2244.
connect'smapStateToPropsandmapDispatchToPropsare typed as unions that include both a "factory" form (() => (state) => props) and a plain form. A factory is structurally assignable to its plain counterpart, so the compiler has to pick a "first" candidate to inferTStateProps/TDispatchPropsfrom — andtscand the new native compiler (tsgo/ TS 7) order union members differently. One of them ends up inferring the wrong candidate and the connected component's props collapse to{}(a required prop shows up as "missing" at the call site).As Anders suggested in the upstream analysis (microsoft/typescript-go#977), the robust fix is to break the union into separate overloads listed in order of preference rather than relying on union ordering. So I've split the affected overloads with the factory form listed first, followed by the plain form. A plain object-returning function isn't assignable to the factory signature, so a factory matches the first overload and everything else falls through — deterministically, and independent of the compiler.
A couple of notes on scope:
mapDispatchToPropsdoesn't get its own factory overload: factories and dispatch functions are already matched by the function-form overloads that precede it, so the object overloads only need the plain (MapDispatchToProps) parameter. This keeps the overload count from exploding.mergePropsoverloads deliberately keep the union parameters. TheremergePropsreceivesstateProps/dispatchPropsas contextually-typed (non-inferring) parameters, so those types can only come from the map functions — and a leading factory overload would swallow a plain map function and collapse the inferred props to{}. Keeping both forms as candidates in a single overload preserves the original behavior. It's documented inline.Types only, no runtime changes.
I added type tests covering the repro cases from the issue (plain/factory
mapStateToProps, the function/factory/object forms ofmapDispatchToProps, a factory + factory combination, and the wrong-return-type cases). They pass under bothtscand the native compiler, and — this is the important part — they stay green even if the union members are reordered, which is the actual failure mode here: reordering the unions on plaintscreproduces the exact errors from the report before this change, and no longer does after it.One caveat worth mentioning: current
tsgodev builds may already infer these cases correctly, but the union ordering is still load-bearing and fragile, and the compiler-side issue was closed as "not planned" — so this makes the types stable regardless of compiler or union order.