Skip to content

fix(mobx): ObservableSet union/intersection/symmetricDifference result ordering#4681

Open
spokodev wants to merge 1 commit into
mobxjs:mainfrom
spokodev:fix/observableset-receiver-order
Open

fix(mobx): ObservableSet union/intersection/symmetricDifference result ordering#4681
spokodev wants to merge 1 commit into
mobxjs:mainfrom
spokodev:fix/observableset-receiver-order

Conversation

@spokodev

@spokodev spokodev commented Jul 2, 2026

Copy link
Copy Markdown

ObservableSet implements Set<T>, so its ES2024 set methods should match native Set result ordering: union appends the argument's new elements after the receiver's, and intersection and symmetricDifference keep the receiver's order. When the argument is a plain (non-observable) Set, union, intersection and symmetricDifference instead delegate to the argument (otherSet.method(this)), so the result comes out in the argument's order.

const s = observable.set([1, 2, 3])
;[...s.union(new Set([3, 4]))]        // was [3, 4, 1, 2], native is [1, 2, 3, 4]
;[...s.intersection(new Set([3, 2]))] // argument-ordered instead of receiver-ordered

Values and membership are correct, so this slipped past the existing tests, which compare with toEqual(new Set([...])) (order-insensitive). It surfaces whenever the result is iterated (spread, Array.from, forEach, rendering a list) after moving from a plain Set to observable.set.

Fix

Build the result from the receiver in every case: return new Set(this).method(otherSet), matching the already-correct difference, isSubsetOf and isSupersetOf. The observable-argument case already used this form (the previous else branch), so the #3919 stack-overflow behavior is unchanged; only the plain-Set path changes, from argument-order to receiver-order. isDisjointFrom is aligned to the same form as well (its boolean result was already correct, so this is only for consistency).

Testing

Added an order-sensitive test to __tests__/base/set.js that compares against a native Set built from the same receiver. It fails before this change; the full set suite (28 tests, including the #3919 case) stays green with it.

union, intersection and symmetricDifference delegated to the argument
when it was a plain Set, so results came out in the argument's order
instead of the receiver's. Build every result from the receiver, as
difference/isSubsetOf/isSupersetOf already do, to match native Set.
@changeset-bot

changeset-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: cf9f892

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
mobx Patch

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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This pull request fixes ObservableSet’s ES2024 Set-method result ordering (union, intersection, symmetricDifference) so it matches native Set semantics when the argument is a plain (non-observable) Set, and aligns isDisjointFrom to the same delegation pattern for consistency.

Changes:

  • Update ObservableSet ES2024 set methods to always compute results from the receiver via new Set(this).<method>(otherSet), ensuring receiver-based ordering.
  • Add an order-sensitive test that compares ObservableSet iteration order against a native Set copy using the same operations.
  • Add a patch changeset documenting the ordering fix.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
packages/mobx/src/types/observableset.ts Ensure ES2024 Set operations on ObservableSet preserve receiver-based result ordering by delegating through new Set(this) consistently.
packages/mobx/tests/base/set.js Add an order-sensitive regression test to verify behavior matches native Set when operating with a plain Set argument.
.changeset/fix-observableset-receiver-order.md Document the behavioral fix as a patch-level change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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.

2 participants