diff --git a/.changeset/neat-ants-relate.md b/.changeset/neat-ants-relate.md new file mode 100644 index 000000000..bade8e7ef --- /dev/null +++ b/.changeset/neat-ants-relate.md @@ -0,0 +1,5 @@ +--- +"mobx": patch +--- + +Update typescript version to 5.6.2 and added support for esnext iterator helpers diff --git a/package.json b/package.json index 363763f23..5f886c3f5 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ ], "resolutions": { "jest": "^29.5.0", - "typescript": "^5.5.2", + "typescript": "^5.6.2", "recast": "^0.23.1" }, "repository": { @@ -69,7 +69,7 @@ "tape": "^5.0.1", "ts-jest": "^29.0.5", "tsdx": "^0.14.1", - "typescript": "^5.5.2" + "typescript": "^5.6.2" }, "husky": { "hooks": { diff --git a/packages/mobx/__tests__/v5/base/map.js b/packages/mobx/__tests__/v5/base/map.js index 327e73411..c21b5b11d 100644 --- a/packages/mobx/__tests__/v5/base/map.js +++ b/packages/mobx/__tests__/v5/base/map.js @@ -915,6 +915,34 @@ test("maps.values, keys and maps.entries are iterables", () => { expect(Array.from(x.keys())).toEqual(["x", "y"]) }) +// Test support for [iterator-helpers](https://github.com/tc39/proposal-iterator-helpers) +test("esnext iterator helpers support", () => { + const map = mobx.observable( + new Map([ + ["x", [1, 2]], + ["y", [3, 4]] + ]) + ) + + expect(Array.from(map.keys().map(value => value))).toEqual(["x", "y"]) + expect(Array.from(map.values().map(value => value))).toEqual([ + [1, 2], + [3, 4] + ]) + expect(Array.from(map.entries().map(([, value]) => value))).toEqual([ + [1, 2], + [3, 4] + ]) + + expect(Array.from(map.entries().take(1))).toEqual([["x", [1, 2]]]) + expect(Array.from(map.entries().drop(1))).toEqual([["y", [3, 4]]]) + expect(Array.from(map.entries().filter(([key]) => key === "y"))).toEqual([["y", [3, 4]]]) + expect(Array.from(map.entries().find(([key]) => key === "y"))).toEqual(["y", [3, 4]]) + expect(map.entries().toArray()).toEqual(Array.from(map)) + + expect(map.entries().toString()).toEqual("[object MapIterator]") +}) + test("toStringTag", () => { const x = mobx.observable.map({ x: 1, y: 2 }) expect(x[Symbol.toStringTag]).toBe("Map") diff --git a/packages/mobx/__tests__/v5/base/set.js b/packages/mobx/__tests__/v5/base/set.js index 6ffcf79f4..c956775ba 100644 --- a/packages/mobx/__tests__/v5/base/set.js +++ b/packages/mobx/__tests__/v5/base/set.js @@ -201,6 +201,34 @@ test("set should support iterall / iterable ", () => { expect(leech(a.values())).toEqual([1, 2]) }) +// Test support for [iterator-helpers](https://github.com/tc39/proposal-iterator-helpers) +test("esnext iterator helpers support", () => { + const set = mobx.observable( + new Set([ + [1, 2], + [3, 4] + ]) + ) + + expect(Array.from(set.values().map(value => value))).toEqual([ + [1, 2], + [3, 4] + ]) + + expect(Array.from(set.entries().map(([, value]) => value))).toEqual([ + [1, 2], + [3, 4] + ]) + + expect(Array.from(set.values().take(1))).toEqual([[1, 2]]) + expect(Array.from(set.values().drop(1))).toEqual([[3, 4]]) + expect(Array.from(set.values().filter(value => value[0] === 3))).toEqual([[3, 4]]) + expect(Array.from(set.values().find(value => value[0] === 3))).toEqual([3, 4]) + expect(Array.from(set.values().flatMap(value => value))).toEqual([1, 2, 3, 4]) + + expect(set.entries().toString()).toEqual("[object SetIterator]") +}) + test("support for ES6 Set", () => { const x = new Set() x.add(1) diff --git a/packages/mobx/src/types/observablemap.ts b/packages/mobx/src/types/observablemap.ts index 3cf868b25..e47eead41 100644 --- a/packages/mobx/src/types/observablemap.ts +++ b/packages/mobx/src/types/observablemap.ts @@ -9,6 +9,7 @@ import { checkIfStateModificationsAreAllowed, createAtom, createInstanceofPredicate, + makeIterable, deepEnhancer, getNextId, getPlainObjectKeys, @@ -19,7 +20,6 @@ import { isPlainES6Map, isPlainObject, isSpyEnabled, - makeIterable, notifyListeners, referenceEnhancer, registerInterceptor, @@ -296,15 +296,15 @@ export class ObservableMap return value } - keys(): IterableIterator { + keys(): MapIterator { this.keysAtom_.reportObserved() return this.data_.keys() } - values(): IterableIterator { + values(): MapIterator { const self = this const keys = this.keys() - return makeIterable({ + return makeIterableForMap({ next() { const { done, value } = keys.next() return { @@ -315,10 +315,10 @@ export class ObservableMap }) } - entries(): IterableIterator> { + entries(): MapIterator> { const self = this const keys = this.keys() - return makeIterable({ + return makeIterableForMap({ next() { const { done, value } = keys.next() return { @@ -490,6 +490,11 @@ export var isObservableMap = createInstanceofPredicate("ObservableMap", Observab thing: any ) => thing is ObservableMap +function makeIterableForMap(iterator: Iterator): MapIterator { + iterator[Symbol.toStringTag] = "MapIterator" + return makeIterable(iterator) +} + function convertToMap(dataStructure: any): Map { if (isES6Map(dataStructure) || isObservableMap(dataStructure)) { return dataStructure diff --git a/packages/mobx/src/types/observableset.ts b/packages/mobx/src/types/observableset.ts index fb6e77d5a..01aabec94 100644 --- a/packages/mobx/src/types/observableset.ts +++ b/packages/mobx/src/types/observableset.ts @@ -13,6 +13,7 @@ import { notifyListeners, spyReportEnd, createInstanceofPredicate, + makeIterable, hasInterceptors, interceptChange, IInterceptable, @@ -20,7 +21,6 @@ import { registerInterceptor, checkIfStateModificationsAreAllowed, untracked, - makeIterable, transaction, isES6Set, IAtom, @@ -214,33 +214,33 @@ export class ObservableSet implements Set, IInterceptable({ + return makeIterableForSet<[T, T]>({ next() { const index = nextIndex nextIndex += 1 return index < values.length ? { value: [keys[index], values[index]], done: false } - : { done: true } + : { value: undefined, done: true } } - } as any) + }) } - keys(): IterableIterator { + keys(): SetIterator { return this.values() } - values(): IterableIterator { + values(): SetIterator { this.atom_.reportObserved() const self = this let nextIndex = 0 const observableValues = Array.from(this.data_.values()) - return makeIterable({ + return makeIterableForSet({ next() { return nextIndex < observableValues.length ? { value: self.dehanceValue_(observableValues[nextIndex++]), done: false } - : { done: true } + : { value: undefined, done: true } } - } as any) + }) } intersection(otherSet: ReadonlySetLike | Set): Set { @@ -343,3 +343,8 @@ export class ObservableSet implements Set, IInterceptable thing is ObservableSet + +function makeIterableForSet(iterator: Iterator): SetIterator { + iterator[Symbol.toStringTag] = "SetIterator" + return makeIterable(iterator) +} diff --git a/packages/mobx/src/utils/iterable.ts b/packages/mobx/src/utils/iterable.ts index 2dde97b41..c05384ef0 100644 --- a/packages/mobx/src/utils/iterable.ts +++ b/packages/mobx/src/utils/iterable.ts @@ -1,8 +1,5 @@ -export function makeIterable(iterator: Iterator): IterableIterator { - iterator[Symbol.iterator] = getSelf - return iterator as any -} - -function getSelf() { - return this +export function makeIterable( + iterator: Iterator +): IteratorObject { + return Object.assign(Object.create(Iterator.prototype), iterator) } diff --git a/yarn.lock b/yarn.lock index 95519581e..bafb1d673 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13579,10 +13579,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@^3.7.3, typescript@^5.5.2: - version "5.5.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.2.tgz#c26f023cb0054e657ce04f72583ea2d85f8d0507" - integrity sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew== +typescript@^3.7.3, 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== uglify-js@^3.1.4: version "3.17.4"