Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Typescript 5.6.x support by introducing esnext iterator helpers (#3927) #3935

Merged
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/neat-ants-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"mobx": patch
---

Update typescript version to 5.6.2 and added support for esnext iterator helpers
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
],
"resolutions": {
"jest": "^29.5.0",
"typescript": "^5.5.2",
"typescript": "^5.6.2",
"recast": "^0.23.1"
},
"repository": {
Expand Down Expand Up @@ -68,7 +68,7 @@
"tape": "^5.0.1",
"ts-jest": "^29.0.5",
"tsdx": "^0.14.1",
"typescript": "^5.5.2"
"typescript": "^5.6.2"
},
"husky": {
"hooks": {
Expand Down
28 changes: 28 additions & 0 deletions packages/mobx/__tests__/v5/base/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
28 changes: 28 additions & 0 deletions packages/mobx/__tests__/v5/base/set.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
17 changes: 11 additions & 6 deletions packages/mobx/src/types/observablemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
checkIfStateModificationsAreAllowed,
createAtom,
createInstanceofPredicate,
makeIterable,
deepEnhancer,
getNextId,
getPlainObjectKeys,
Expand All @@ -19,7 +20,6 @@ import {
isPlainES6Map,
isPlainObject,
isSpyEnabled,
makeIterable,
notifyListeners,
referenceEnhancer,
registerInterceptor,
Expand Down Expand Up @@ -296,15 +296,15 @@ export class ObservableMap<K = any, V = any>
return value
}

keys(): IterableIterator<K> {
keys(): MapIterator<K> {
this.keysAtom_.reportObserved()
return this.data_.keys()
}

values(): IterableIterator<V> {
values(): MapIterator<V> {
const self = this
const keys = this.keys()
return makeIterable({
return makeIterableForMap({
next() {
const { done, value } = keys.next()
return {
Expand All @@ -315,10 +315,10 @@ export class ObservableMap<K = any, V = any>
})
}

entries(): IterableIterator<IMapEntry<K, V>> {
entries(): MapIterator<IMapEntry<K, V>> {
const self = this
const keys = this.keys()
return makeIterable({
return makeIterableForMap({
next() {
const { done, value } = keys.next()
return {
Expand Down Expand Up @@ -490,6 +490,11 @@ export var isObservableMap = createInstanceofPredicate("ObservableMap", Observab
thing: any
) => thing is ObservableMap<any, any>

function makeIterableForMap<T>(iterator: Iterator<T>): MapIterator<T> {
iterator[Symbol.toStringTag] = "MapIterator"
return makeIterable<T, BuiltinIteratorReturn>(iterator)
}

function convertToMap(dataStructure: any): Map<any, any> {
if (isES6Map(dataStructure) || isObservableMap(dataStructure)) {
return dataStructure
Expand Down
23 changes: 14 additions & 9 deletions packages/mobx/src/types/observableset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import {
notifyListeners,
spyReportEnd,
createInstanceofPredicate,
makeIterable,
hasInterceptors,
interceptChange,
IInterceptable,
IInterceptor,
registerInterceptor,
checkIfStateModificationsAreAllowed,
untracked,
makeIterable,
transaction,
isES6Set,
IAtom,
Expand Down Expand Up @@ -214,33 +214,33 @@ export class ObservableSet<T = any> implements Set<T>, IInterceptable<ISetWillCh
let nextIndex = 0
const keys = Array.from(this.keys())
const values = Array.from(this.values())
return makeIterable<[T, T]>({
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<T> {
keys(): SetIterator<T> {
return this.values()
}

values(): IterableIterator<T> {
values(): SetIterator<T> {
this.atom_.reportObserved()
const self = this
let nextIndex = 0
const observableValues = Array.from(this.data_.values())
return makeIterable<T>({
return makeIterableForSet({
next() {
return nextIndex < observableValues.length
? { value: self.dehanceValue_(observableValues[nextIndex++]), done: false }
: { done: true }
: { value: undefined, done: true }
}
} as any)
})
}

intersection<U>(otherSet: ReadonlySetLike<U> | Set<U>): Set<T & U> {
Expand Down Expand Up @@ -343,3 +343,8 @@ export class ObservableSet<T = any> implements Set<T>, IInterceptable<ISetWillCh
export var isObservableSet = createInstanceofPredicate("ObservableSet", ObservableSet) as (
thing: any
) => thing is ObservableSet<any>

function makeIterableForSet<T>(iterator: Iterator<T>): SetIterator<T> {
iterator[Symbol.toStringTag] = "SetIterator"
return makeIterable<T, BuiltinIteratorReturn>(iterator)
}
11 changes: 4 additions & 7 deletions packages/mobx/src/utils/iterable.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
export function makeIterable<T>(iterator: Iterator<T>): IterableIterator<T> {
iterator[Symbol.iterator] = getSelf
return iterator as any
}

function getSelf() {
return this
export function makeIterable<T, TReturn = unknown>(
iterator: Iterator<T>
): IteratorObject<T, TReturn> {
return Object.assign(Object.create(Iterator.prototype), iterator)
Copy link
Contributor Author

@tonyraoul tonyraoul Oct 8, 2024

Choose a reason for hiding this comment

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

Intentionally avoiding the usage of Iterator.from due to limited availability, using this instead to conditionally add helper functions IIF they are available within runtime either natively or via polyfill.

}
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13588,10 +13588,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"
Expand Down