Skip to content

Fix Reorder.Group to accept union array types#3649

Open
mattgperry wants to merge 1 commit intomainfrom
worktree-fix-issue-2905
Open

Fix Reorder.Group to accept union array types#3649
mattgperry wants to merge 1 commit intomainfrom
worktree-fix-issue-2905

Conversation

@mattgperry
Copy link
Collaborator

Summary

Fixes #2905

Reorder.Group's values prop was typed as V[] with a single generic element type V, which prevented passing union array types like number[] | string[]. TypeScript would infer V = number from the first union member and then reject string[].

Cause: The external type signature used V as the element type, so values: V[] couldn't represent number[] | string[] (a union of arrays is not the same as an array of unions).

Fix: Changed the external type assertion to be generic over the full array type (Values extends any[]) instead of just the element type. The values prop now accepts Values directly, and onReorder returns Values, so union array types flow through correctly. The internal implementation is unchanged — it derives the element type as Values[number] where needed.

This is a backwards-compatible change: existing code using string[], number[], or MyObject[] continues to work exactly as before.

Test plan

  • Added unit test that uses useState<number[] | string[]> with Reorder.Group — verifies the TypeScript compilation and rendering
  • Existing Reorder tests pass (ref hydration, virtualized list reorder)
  • Full build passes (yarn build)

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link

greptile-apps bot commented Mar 17, 2026

Greptile Summary

This PR fixes a TypeScript-only issue with Reorder.Group where the values prop could not accept union array types like number[] | string[]. The root cause was that the external generic was parameterised over the element type V, so values: V[] couldn't represent a union of arrays. The fix re-parameterises the exported type cast over the full array type (Values extends any[]) and derives the element type as Values[number] where the internal implementation needs it.

  • Type fix (Group.tsx): The forwardRef cast now uses Values extends any[] as its generic, accepts values: Values directly, and exposes onReorder: (newOrder: Values) => void. The internal ReorderGroupComponent is completely unchanged — the element type for context/register logic continues to come from the internal Props<V> interface.
  • New test (index.test.tsx): Adds a test that instantiates useState<number[] | string[]> and passes it to Reorder.Group, verifying both TypeScript acceptance (the file must compile) and correct runtime rendering of list items.
  • Backwards compatibility: Fully preserved — existing usages typed as string[], number[], or custom object arrays still infer Values as that concrete array type and behave identically.

Confidence Score: 5/5

  • This PR is safe to merge — it is a backwards-compatible TypeScript type-only change with no runtime behaviour modifications.
  • The internal ReorderGroupComponent implementation is untouched; the change is limited to the exported type cast. The Values[number] indexed-access pattern is a well-established TypeScript idiom for extracting element types, and the fix correctly threads union array types through both values and onReorder. A dedicated regression test confirms the scenario compiles and renders correctly. No runtime risk is introduced.
  • No files require special attention.

Important Files Changed

Filename Overview
packages/framer-motion/src/components/Reorder/Group.tsx Adds a type-level cast to expose Values extends any[] as the generic parameter instead of the element type V, allowing union array types to flow through values and onReorder. Internal implementation is unchanged; Values[number] correctly derives the element type for internal use.
packages/framer-motion/src/components/Reorder/tests/index.test.tsx Adds a regression test that uses `useState<number[]

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["User Code\n&lt;Reorder.Group values={items} onReorder={setItems}&gt;"]
    B["External Type Cast\nReorderGroup\nValues extends any[]"]
    C{"TypeScript\ninfers Values"}
    D["string[]"]
    E["number[]"]
    F["string[] | number[]\n(new - previously broken)"]
    G["Values[number]\nextracts element type"]
    H["Internal ReorderGroupComponent\nProps&lt;V, TagName&gt;\n(unchanged)"]
    I["ReorderContext\nregisterItem / updateOrder"]

    A --> B
    B --> C
    C --> D & E & F
    D & E & F --> G
    G -->|"V = Values[number]"| H
    H --> I
Loading

Last reviewed commit: a25d58a


export const ReorderGroup = /*@__PURE__*/ forwardRef(ReorderGroupComponent) as <
V,
Values extends any[],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Consider unknown[] over any[] for the constraint

Values extends any[] technically allows any to satisfy the constraint unchecked. Using Values extends unknown[] is marginally stricter and prevents any from silently widening through — a common best-practice for generic utilities where you don't need the escape hatch any provides.

Suggested change
Values extends any[],
Values extends unknown[],

This is backwards-compatible: all existing concrete types (string[], number[], MyObject[], string[] | number[]) satisfy unknown[] just as they satisfy any[].

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Reorder.Group won't accept string[] | number[] (or similar)

1 participant