diff --git a/package.json b/package.json index 5dbceb97..ce8b2f91 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "tslib": "^2.7.0", "typedoc": "^0.26.7", "typedoc-plugin-markdown": "^4.2.8", - "typescript": "^5.6.2", + "typescript": "^5.6.3", "yargs": "^17.7.2" }, "config": { diff --git a/src/set.ts b/src/set.ts index b0854192..62b4fd53 100644 --- a/src/set.ts +++ b/src/set.ts @@ -151,4 +151,35 @@ export const setHandler = { }, }; +if (Set.prototype.difference) { + // for compatibility with new Set methods + // https://github.com/tc39/proposal-set-methods + Object.assign(setHandler, { + intersection(this: Set, other: ReadonlySetLike): Set { + return Set.prototype.intersection.call(new Set(this.values()), other); + }, + union(this: Set, other: ReadonlySetLike): Set { + return Set.prototype.union.call(new Set(this.values()), other); + }, + difference(this: Set, other: ReadonlySetLike): Set { + return Set.prototype.difference.call(new Set(this.values()), other); + }, + symmetricDifference(this: Set, other: ReadonlySetLike): Set { + return Set.prototype.symmetricDifference.call( + new Set(this.values()), + other + ); + }, + isSubsetOf(this: Set, other: ReadonlySetLike): boolean { + return Set.prototype.isSubsetOf.call(new Set(this.values()), other); + }, + isSupersetOf(this: Set, other: ReadonlySetLike): boolean { + return Set.prototype.isSupersetOf.call(new Set(this.values()), other); + }, + isDisjointFrom(this: Set, other: ReadonlySetLike): boolean { + return Set.prototype.isDisjointFrom.call(new Set(this.values()), other); + }, + }); +} + export const setHandlerKeys = Reflect.ownKeys(setHandler); diff --git a/src/utils/copy.ts b/src/utils/copy.ts index f53aa257..640ff3ae 100644 --- a/src/utils/copy.ts +++ b/src/utils/copy.ts @@ -34,7 +34,9 @@ export function shallowCopy(original: any, options?: Options) { if (Array.isArray(original)) { return Array.prototype.concat.call(original); } else if (original instanceof Set) { - return new Set(original.values()); + return Set.prototype.difference + ? Set.prototype.difference.call(original, new Set()) + : new Set(original.values()); } else if (original instanceof Map) { return new Map(original); } else if ( diff --git a/test/benchmark/results/result.json b/test/benchmark/results/result.json index f398b69c..1aa295c4 100644 --- a/test/benchmark/results/result.json +++ b/test/benchmark/results/result.json @@ -41,10 +41,10 @@ }, "set-batch": { "name": "set-batch", - "avg": 2.501448439449168 + "avg": 2.5015325732958087 }, "set": { "name": "set", - "avg": 3.081842714116322 + "avg": 3.9251446240188272 } } \ No newline at end of file diff --git a/test/benchmark/results/set-batch.jpg b/test/benchmark/results/set-batch.jpg index 3ec54922..5354a96d 100644 Binary files a/test/benchmark/results/set-batch.jpg and b/test/benchmark/results/set-batch.jpg differ diff --git a/test/benchmark/results/set.jpg b/test/benchmark/results/set.jpg index e7976f1a..a3b9ff9b 100644 Binary files a/test/benchmark/results/set.jpg and b/test/benchmark/results/set.jpg differ diff --git a/test/immer-non-support.test.ts b/test/immer-non-support.test.ts index 2d5f7096..8cd28adb 100644 --- a/test/immer-non-support.test.ts +++ b/test/immer-non-support.test.ts @@ -617,3 +617,28 @@ test('#61 - type issue: current of Draft type should return T type', () => { }); } }); + +test('set - new Set API', () => { + // @ts-ignore + if (!Set.prototype.difference) { + console.warn('Set.prototype.difference is not supported'); + return; + } + { + enableMapSet(); + const odds = new Set([1, 3, 5, 7, 9]); + const squares = new Set([1, 4, 9]); + const state = produce(odds, (draft) => { + // @ts-ignore + expect(draft.intersection(squares)).toEqual(new Set([])); // it should be `new Set([1, 9])` + }); + } + { + const odds = new Set([1, 3, 5, 7, 9]); + const squares = new Set([1, 4, 9]); + const state = create(odds, (draft) => { + // @ts-ignore + expect(draft.intersection(squares)).toEqual(new Set([1, 9])); + }); + } +}); diff --git a/test/index.test.ts b/test/index.test.ts index 51224a11..b807be91 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -4103,3 +4103,118 @@ test('#61 - type issue: current of Draft type should return T type', () => { x: { y: new Set(['a', 'b']) }, }); }); + +describe('set - new API', () => { + // @ts-ignore + if (!Set.prototype.difference) { + return; + } + test('set - without Set.prototype.difference', () => { + // @ts-ignore + const difference = Set.prototype.difference; + // @ts-ignore + delete Set.prototype.difference; + const odds = new Set([{a: 1}]); + const state = create({ odds }, (draft) => { + // @ts-ignore + draft.odds.values().next().value.a = 2; + }); + // @ts-ignore + Set.prototype.difference = difference; + }); + + test('set - Set.prototype.intersection', () => { + const odds = new Set([1, 3, 5, 7, 9]); + const squares = new Set([1, 4, 9]); + const state = create(odds, (draft) => { + // @ts-ignore + expect(draft.intersection(squares)).toEqual(new Set([1, 9])); + }); + }); + + test('set - Set.prototype.union', () => { + const evens = new Set([2, 4, 6, 8]); + const squares = new Set([1, 4, 9]); + const state = create(evens, (draft) => { + // @ts-ignore + expect(draft.union(squares)).toEqual(new Set([2, 4, 6, 8, 1, 9])); + }); + }); + + test('set - Set.prototype.difference', () => { + const odds = new Set([1, 3, 5, 7, 9]); + const squares = new Set([1, 4, 9]); + const state = create(odds, (draft) => { + // @ts-ignore + expect(draft.difference(squares)).toEqual(new Set([3, 5, 7])); + }); + }); + + test('set - Set.prototype.symmetricDifference', () => { + const evens = new Set([2, 4, 6, 8]); + const squares = new Set([1, 4, 9]); + const state = create(evens, (draft) => { + // @ts-ignore + expect(draft.symmetricDifference(squares)).toEqual( + new Set([2, 6, 8, 1, 9]) + ); + }); + }); + + test('set - Set.prototype.isSubsetOf', () => { + { + const fours = new Set([4, 8, 12, 16]); + const evens = new Set([2, 4, 6, 8, 10, 12, 14, 16, 18]); + const state = create(fours, (draft) => { + // @ts-ignore + expect(draft.isSubsetOf(evens)).toBe(true); + }); + } + { + const primes = new Set([2, 3, 5, 7, 11, 13, 17, 19]); + const odds = new Set([3, 5, 7, 9, 11, 13, 15, 17, 19]); + const state = create(primes, (draft) => { + // @ts-ignore + expect(draft.isSubsetOf(odds)).toBe(false); + }); + } + }); + + test('set - Set.prototype.isSupersetOf', () => { + { + const evens = new Set([2, 4, 6, 8, 10, 12, 14, 16, 18]); + const fours = new Set([4, 8, 12, 16]); + const state = create(evens, (draft) => { + // @ts-ignore + expect(draft.isSupersetOf(fours)).toBe(true); + }); + } + { + const primes = new Set([2, 3, 5, 7, 11, 13, 17, 19]); + const odds = new Set([3, 5, 7, 9, 11, 13, 15, 17, 19]); + const state = create(odds, (draft) => { + // @ts-ignore + expect(draft.isSupersetOf(primes)).toBe(false); + }); + } + }); + + test('set - Set.prototype.isDisjointFrom', () => { + { + const primes = new Set([2, 3, 5, 7, 11, 13, 17, 19]); + const squares = new Set([1, 4, 9, 16]); + const state = create(primes, (draft) => { + // @ts-ignore + expect(draft.isDisjointFrom(squares)).toBe(true); + }); + } + { + const composites = new Set([4, 6, 8, 9, 10, 12, 14, 15, 16, 18]); + const squares = new Set([1, 4, 9, 16]); + const state = create(composites, (draft) => { + // @ts-ignore + expect(draft.isDisjointFrom(squares)).toBe(false); + }); + } + }); +}); diff --git a/test/performance/new-set-api.jpg b/test/performance/new-set-api.jpg index 30fe4e5d..9c79c50b 100644 Binary files a/test/performance/new-set-api.jpg and b/test/performance/new-set-api.jpg differ diff --git a/test/performance/new-set-api.ts b/test/performance/new-set-api.ts index ce140c4a..1356fd45 100644 --- a/test/performance/new-set-api.ts +++ b/test/performance/new-set-api.ts @@ -124,7 +124,7 @@ const run = (size: number) => { .add( 'Set - shallow copy with difference()', () => { - const state = baseState.difference(new Set()); + const state = Set.prototype.difference.call(baseState, new Set()) }, { onStart: () => { diff --git a/yarn.lock b/yarn.lock index 091c97de..27c8c3d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6834,10 +6834,10 @@ typedoc@^0.26.7: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.2.tgz#891e1a90c5189d8506af64b9ef929fca99ba1ee5" integrity sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw== -typescript@^5.6.2: - version "5.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" - integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== +typescript@^5.6.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6"