Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-observableset-receiver-order.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"mobx": patch
---

Fix ObservableSet union, intersection and symmetricDifference to return results in receiver order, matching native Set, when the argument is a plain Set.
11 changes: 11 additions & 0 deletions packages/mobx/__tests__/base/set.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,17 @@ describe("The Set object methods do what they are supposed to do", () => {
expect(isDisjointFromObservableResult).toBeTruthy()
})

test("set methods preserve receiver order (matches native Set)", () => {
const nativeCopy = new Set(reactiveSet)
const other = new Set([6, 2, 1])

expect([...reactiveSet.union(other)]).toEqual([...nativeCopy.union(other)])
expect([...reactiveSet.intersection(other)]).toEqual([...nativeCopy.intersection(other)])
expect([...reactiveSet.symmetricDifference(other)]).toEqual([
...nativeCopy.symmetricDifference(other)
])
})

test("with ObservableSet #3919", () => {
const intersectionObservableResult = reactiveSet.intersection(set([1, 2, 6]))
const unionObservableResult = reactiveSet.union(set([1, 2, 6]))
Expand Down
39 changes: 8 additions & 31 deletions packages/mobx/src/types/observableset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,14 @@ export type ISetWillDeleteChange<T = any> = {
type: "delete"
object: ObservableSet<T>
oldValue: T
};
}
export type ISetWillAddChange<T = any> = {
type: "add"
object: ObservableSet<T>
newValue: T
};
}

export type ISetWillChange<T = any> =
| ISetWillDeleteChange<T>
| ISetWillAddChange<T>
export type ISetWillChange<T = any> = ISetWillDeleteChange<T> | ISetWillAddChange<T>

export class ObservableSet<T = any> implements Set<T>, IInterceptable<ISetWillChange>, IListenable {
[$mobx] = ObservableSetMarker
Expand Down Expand Up @@ -133,8 +131,7 @@ export class ObservableSet<T = any> implements Set<T>, IInterceptable<ISetWillCh
}

// implemented reassignment same as it's done for ObservableMap
value = change.newValue!;

value = change.newValue!
}
if (!this.has(value)) {
transaction(() => {
Expand Down Expand Up @@ -244,34 +241,19 @@ export class ObservableSet<T = any> implements Set<T>, IInterceptable<ISetWillCh
}

intersection<U>(otherSet: ReadonlySetLike<U> | Set<U>): Set<T & U> {
if (isES6Set(otherSet) && !isObservableSet(otherSet)) {
return otherSet.intersection(this)
} else {
const dehancedSet = new Set(this)
return dehancedSet.intersection(otherSet)
}
return new Set(this).intersection(otherSet)
}

union<U>(otherSet: ReadonlySetLike<U> | Set<U>): Set<T | U> {
if (isES6Set(otherSet) && !isObservableSet(otherSet)) {
return otherSet.union(this)
} else {
const dehancedSet = new Set(this)
return dehancedSet.union(otherSet)
}
return new Set(this).union(otherSet)
}

difference<U>(otherSet: ReadonlySetLike<U>): Set<T> {
return new Set(this).difference(otherSet)
}

symmetricDifference<U>(otherSet: ReadonlySetLike<U> | Set<U>): Set<T | U> {
if (isES6Set(otherSet) && !isObservableSet(otherSet)) {
return otherSet.symmetricDifference(this)
} else {
const dehancedSet = new Set(this)
return dehancedSet.symmetricDifference(otherSet)
}
return new Set(this).symmetricDifference(otherSet)
}

isSubsetOf(otherSet: ReadonlySetLike<unknown>): boolean {
Expand All @@ -283,12 +265,7 @@ export class ObservableSet<T = any> implements Set<T>, IInterceptable<ISetWillCh
}

isDisjointFrom(otherSet: ReadonlySetLike<unknown> | Set<unknown>): boolean {
if (isES6Set(otherSet) && !isObservableSet(otherSet)) {
return otherSet.isDisjointFrom(this)
} else {
const dehancedSet = new Set(this)
return dehancedSet.isDisjointFrom(otherSet)
}
return new Set(this).isDisjointFrom(otherSet)
}

replace(other: ObservableSet<T> | IObservableSetInitialValues<T>): ObservableSet<T> {
Expand Down