Skip to content

Commit c9207d8

Browse files
committed
Increase entries/values compatibility
1 parent cdccf1a commit c9207d8

File tree

2 files changed

+59
-7
lines changed

2 files changed

+59
-7
lines changed

__tests__/map-set.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"use strict"
2-
import {vi} from "vitest"
2+
import {expect, vi} from "vitest"
33
import {
44
Immer,
55
nothing,
@@ -331,6 +331,36 @@ function runBaseTest(name, autoFreeze, useListener) {
331331

332332
expect(Array.from(newSet)).toEqual([items[0], items[1]])
333333
})
334+
335+
it("IterableIterator should return itself", () => {
336+
const baseState = {
337+
map: new Map([1, 2, 3].map(i => [i, `Item ${i}`]))
338+
}
339+
340+
produce(baseState, draft => {
341+
const it = draft.map.values()
342+
expect(it.next()).toEqual({value: "Item 1", done: false})
343+
344+
const itOfIt = it[Symbol.iterator]()
345+
expect(itOfIt.next()).toEqual({value: "Item 2", done: false})
346+
expect(itOfIt).toBe(it)
347+
348+
const it2 = draft.map.values()
349+
expect(it2.next()).toEqual({value: "Item 1", done: false})
350+
})
351+
})
352+
353+
it("is compatible with ES2025 features", () => {
354+
const baseState = {
355+
map: new Map([1, 2, 3].map(i => [i, `Item ${i}`]))
356+
}
357+
358+
const result = produce(baseState, draft => {
359+
draft.map = new Map(draft.map.entries().filter(([k]) => k % 2 === 1))
360+
})
361+
362+
expect(result.map.keys().toArray()).toEqual([1, 3])
363+
})
334364
})
335365
describe("set issues " + name, () => {
336366
test("#819.A - maintains order when adding", () => {

src/plugins/mapset.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ import {
2020
handleCrossReference
2121
} from "../internal"
2222

23+
declare global {
24+
// `Iterator.from` was added in ES2025.
25+
var Iterator:
26+
| undefined
27+
| {
28+
from<T, TReturn>(iterable: Iterator<T, TReturn>): IterableIterator<T>
29+
}
30+
}
31+
2332
export function enableMapSet() {
2433
class DraftMap extends Map {
2534
[DRAFT_STATE]: MapState
@@ -126,8 +135,7 @@ export function enableMapSet() {
126135

127136
values(): IterableIterator<any> {
128137
const iterator = this.keys()
129-
return {
130-
[Symbol.iterator]: () => this.values(),
138+
return iteratorFrom({
131139
next: () => {
132140
const r = iterator.next()
133141
/* istanbul ignore next */
@@ -138,13 +146,12 @@ export function enableMapSet() {
138146
value
139147
}
140148
}
141-
} as any
149+
})
142150
}
143151

144152
entries(): IterableIterator<[any, any]> {
145153
const iterator = this.keys()
146-
return {
147-
[Symbol.iterator]: () => this.entries(),
154+
return iteratorFrom({
148155
next: () => {
149156
const r = iterator.next()
150157
/* istanbul ignore next */
@@ -155,14 +162,29 @@ export function enableMapSet() {
155162
value: [r.value, value]
156163
}
157164
}
158-
} as any
165+
})
159166
}
160167

161168
[Symbol.iterator]() {
162169
return this.entries()
163170
}
164171
}
165172

173+
function iteratorFrom<T, TReturn>(
174+
iterable: Iterator<T, TReturn>
175+
): IterableIterator<T> {
176+
if (typeof Iterator !== "undefined") {
177+
return Iterator.from(iterable)
178+
}
179+
180+
const iterator: IterableIterator<T> = {
181+
...iterable,
182+
[Symbol.iterator]: () => iterator
183+
}
184+
185+
return iterator
186+
}
187+
166188
function proxyMap_<T extends AnyMap>(
167189
target: T,
168190
parent?: ImmerState

0 commit comments

Comments
 (0)