mobx 6.1.8 → 6.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/CHANGELOG.md +224 -7
  2. package/README.md +54 -52
  3. package/dist/api/annotation.d.ts +6 -12
  4. package/dist/api/autorun.d.ts +4 -4
  5. package/dist/api/flow.d.ts +1 -0
  6. package/dist/api/intercept.d.ts +5 -5
  7. package/dist/api/object-api.d.ts +2 -0
  8. package/dist/api/observable.d.ts +5 -1
  9. package/dist/api/observe.d.ts +4 -4
  10. package/dist/api/tojs.d.ts +4 -1
  11. package/dist/api/when.d.ts +8 -0
  12. package/dist/core/atom.d.ts +1 -1
  13. package/dist/core/computedvalue.d.ts +0 -1
  14. package/dist/core/globalstate.d.ts +4 -0
  15. package/dist/core/reaction.d.ts +2 -2
  16. package/dist/errors.d.ts +4 -2
  17. package/dist/internal.d.ts +1 -0
  18. package/dist/mobx.cjs.development.js +1477 -1719
  19. package/dist/mobx.cjs.development.js.map +1 -1
  20. package/dist/mobx.cjs.production.min.js +1 -1
  21. package/dist/mobx.cjs.production.min.js.map +1 -1
  22. package/dist/mobx.d.ts +1 -1
  23. package/dist/mobx.esm.development.js +1475 -1720
  24. package/dist/mobx.esm.development.js.map +1 -1
  25. package/dist/mobx.esm.js +1492 -1726
  26. package/dist/mobx.esm.js.map +1 -1
  27. package/dist/mobx.esm.production.min.js +1 -1
  28. package/dist/mobx.esm.production.min.js.map +1 -1
  29. package/dist/mobx.umd.development.js +1477 -1719
  30. package/dist/mobx.umd.development.js.map +1 -1
  31. package/dist/mobx.umd.production.min.js +1 -1
  32. package/dist/mobx.umd.production.min.js.map +1 -1
  33. package/dist/types/actionannotation.d.ts +7 -1
  34. package/dist/types/autoannotation.d.ts +3 -0
  35. package/dist/types/observablemap.d.ts +5 -4
  36. package/dist/types/observableobject.d.ts +6 -9
  37. package/dist/types/observableset.d.ts +4 -4
  38. package/dist/types/observablevalue.d.ts +3 -5
  39. package/dist/utils/utils.d.ts +4 -4
  40. package/package.json +1 -1
  41. package/src/api/action.ts +8 -3
  42. package/src/api/annotation.ts +14 -44
  43. package/src/api/autorun.ts +38 -17
  44. package/src/api/computed.ts +5 -2
  45. package/src/api/configure.ts +6 -2
  46. package/src/api/decorators.ts +1 -1
  47. package/src/api/extendobservable.ts +12 -6
  48. package/src/api/extras.ts +4 -2
  49. package/src/api/flow.ts +17 -5
  50. package/src/api/intercept-read.ts +4 -2
  51. package/src/api/intercept.ts +10 -7
  52. package/src/api/iscomputed.ts +14 -8
  53. package/src/api/isobservable.ts +10 -4
  54. package/src/api/makeObservable.ts +35 -36
  55. package/src/api/object-api.ts +42 -14
  56. package/src/api/observable.ts +39 -25
  57. package/src/api/observe.ts +9 -6
  58. package/src/api/tojs.ts +20 -10
  59. package/src/api/trace.ts +6 -2
  60. package/src/api/when.ts +34 -9
  61. package/src/core/action.ts +11 -5
  62. package/src/core/atom.ts +9 -2
  63. package/src/core/computedvalue.ts +48 -27
  64. package/src/core/derivation.ts +34 -12
  65. package/src/core/globalstate.ts +25 -7
  66. package/src/core/observable.ts +23 -13
  67. package/src/core/reaction.ts +16 -7
  68. package/src/core/spy.ts +20 -7
  69. package/src/errors.ts +16 -3
  70. package/src/internal.ts +1 -0
  71. package/src/mobx.ts +6 -2
  72. package/src/types/actionannotation.ts +30 -52
  73. package/src/types/autoannotation.ts +107 -0
  74. package/src/types/computedannotation.ts +7 -37
  75. package/src/types/dynamicobject.ts +12 -6
  76. package/src/types/flowannotation.ts +40 -41
  77. package/src/types/intercept-utils.ts +9 -3
  78. package/src/types/legacyobservablearray.ts +26 -3
  79. package/src/types/listen-utils.ts +6 -2
  80. package/src/types/modifiers.ts +52 -16
  81. package/src/types/observableannotation.ts +7 -34
  82. package/src/types/observablearray.ts +106 -45
  83. package/src/types/observablemap.ts +71 -35
  84. package/src/types/observableobject.ts +88 -82
  85. package/src/types/observableset.ts +32 -13
  86. package/src/types/observablevalue.ts +16 -10
  87. package/src/types/overrideannotation.ts +4 -2
  88. package/src/types/type-utils.ts +34 -12
  89. package/src/utils/comparer.ts +5 -1
  90. package/src/utils/eq.ts +45 -15
  91. package/src/utils/utils.ts +39 -16
@@ -9,7 +9,12 @@ import {
9
9
  isObservableObject,
10
10
  isPlainObject,
11
11
  observable,
12
- die
12
+ die,
13
+ isAction,
14
+ autoAction,
15
+ flow,
16
+ isFlow,
17
+ isGenerator
13
18
  } from "../internal"
14
19
 
15
20
  export interface IEnhancer<T> {
@@ -18,30 +23,58 @@ export interface IEnhancer<T> {
18
23
 
19
24
  export function deepEnhancer(v, _, name) {
20
25
  // it is an observable already, done
21
- if (isObservable(v)) return v
26
+ if (isObservable(v)) {
27
+ return v
28
+ }
22
29
 
23
30
  // something that can be converted and mutated?
24
- if (Array.isArray(v)) return observable.array(v, { name })
25
- if (isPlainObject(v)) return observable.object(v, undefined, { name })
26
- if (isES6Map(v)) return observable.map(v, { name })
27
- if (isES6Set(v)) return observable.set(v, { name })
28
-
31
+ if (Array.isArray(v)) {
32
+ return observable.array(v, { name })
33
+ }
34
+ if (isPlainObject(v)) {
35
+ return observable.object(v, undefined, { name })
36
+ }
37
+ if (isES6Map(v)) {
38
+ return observable.map(v, { name })
39
+ }
40
+ if (isES6Set(v)) {
41
+ return observable.set(v, { name })
42
+ }
43
+ if (typeof v === "function" && !isAction(v) && !isFlow(v)) {
44
+ if (isGenerator(v)) {
45
+ return flow(v)
46
+ } else {
47
+ return autoAction(name, v)
48
+ }
49
+ }
29
50
  return v
30
51
  }
31
52
 
32
53
  export function shallowEnhancer(v, _, name): any {
33
- if (v === undefined || v === null) return v
34
- if (isObservableObject(v) || isObservableArray(v) || isObservableMap(v) || isObservableSet(v))
54
+ if (v === undefined || v === null) {
55
+ return v
56
+ }
57
+ if (isObservableObject(v) || isObservableArray(v) || isObservableMap(v) || isObservableSet(v)) {
35
58
  return v
36
- if (Array.isArray(v)) return observable.array(v, { name, deep: false })
37
- if (isPlainObject(v)) return observable.object(v, undefined, { name, deep: false })
38
- if (isES6Map(v)) return observable.map(v, { name, deep: false })
39
- if (isES6Set(v)) return observable.set(v, { name, deep: false })
59
+ }
60
+ if (Array.isArray(v)) {
61
+ return observable.array(v, { name, deep: false })
62
+ }
63
+ if (isPlainObject(v)) {
64
+ return observable.object(v, undefined, { name, deep: false })
65
+ }
66
+ if (isES6Map(v)) {
67
+ return observable.map(v, { name, deep: false })
68
+ }
69
+ if (isES6Set(v)) {
70
+ return observable.set(v, { name, deep: false })
71
+ }
40
72
 
41
- if (__DEV__)
73
+ if (__DEV__) {
42
74
  die(
43
75
  "The shallow modifier / decorator can only used in combination with arrays, objects, maps and sets"
44
76
  )
77
+ }
45
78
  }
46
79
 
47
80
  export function referenceEnhancer(newValue?) {
@@ -50,8 +83,11 @@ export function referenceEnhancer(newValue?) {
50
83
  }
51
84
 
52
85
  export function refStructEnhancer(v, oldValue): any {
53
- if (__DEV__ && isObservable(v))
86
+ if (__DEV__ && isObservable(v)) {
54
87
  die(`observable.struct should not be used with observable values`)
55
- if (deepEqual(v, oldValue)) return oldValue
88
+ }
89
+ if (deepEqual(v, oldValue)) {
90
+ return oldValue
91
+ }
56
92
  return v
57
93
  }
@@ -1,12 +1,9 @@
1
1
  import {
2
2
  ObservableObjectAdministration,
3
- getDescriptor,
4
3
  deepEnhancer,
5
4
  die,
6
5
  Annotation,
7
- recordAnnotationApplied,
8
- objectPrototype,
9
- storedAnnotationsSymbol
6
+ MakeResult
10
7
  } from "../internal"
11
8
 
12
9
  export function createObservableAnnotation(name: string, options?: object): Annotation {
@@ -18,36 +15,12 @@ export function createObservableAnnotation(name: string, options?: object): Anno
18
15
  }
19
16
  }
20
17
 
21
- function make_(adm: ObservableObjectAdministration, key: PropertyKey): void {
22
- let source = adm.target_
23
- // Copy props from proto as well, see test:
24
- // "decorate should work with Object.create"
25
- while (source && source !== objectPrototype) {
26
- const descriptor = getDescriptor(source, key)
27
- if (descriptor) {
28
- assertObservableDescriptor(adm, this, key, descriptor)
29
- const definePropertyOutcome = adm.defineObservableProperty_(
30
- key,
31
- descriptor.value,
32
- this.options_?.enhancer ?? deepEnhancer
33
- )
34
- if (!definePropertyOutcome) {
35
- // Intercepted
36
- return
37
- }
38
- recordAnnotationApplied(adm, this, key)
39
- return
40
- }
41
- source = Object.getPrototypeOf(source)
42
- }
43
- if (!adm.target_[storedAnnotationsSymbol]?.[key]) {
44
- // Throw on missing key, except for decorators:
45
- // Decorator annotations are collected from whole prototype chain.
46
- // When called from super() some props may not exist yet.
47
- // However we don't have to worry about missing prop,
48
- // because the decorator must have been applied to something.
49
- die(1, this.annotationType_, `${adm.name_}.${key.toString()}`)
50
- }
18
+ function make_(
19
+ adm: ObservableObjectAdministration,
20
+ key: PropertyKey,
21
+ descriptor: PropertyDescriptor
22
+ ): MakeResult {
23
+ return this.extend_(adm, key, descriptor, false) === null ? MakeResult.Cancel : MakeResult.Break
51
24
  }
52
25
 
53
26
  function extend_(
@@ -84,8 +84,12 @@ export interface IArrayWillSplice<T = any> {
84
84
  const arrayTraps = {
85
85
  get(target, name) {
86
86
  const adm: ObservableArrayAdministration = target[$mobx]
87
- if (name === $mobx) return adm
88
- if (name === "length") return adm.getArrayLength_()
87
+ if (name === $mobx) {
88
+ return adm
89
+ }
90
+ if (name === "length") {
91
+ return adm.getArrayLength_()
92
+ }
89
93
  if (typeof name === "string" && !isNaN(name as any)) {
90
94
  return adm.get_(parseInt(name))
91
95
  }
@@ -113,7 +117,8 @@ const arrayTraps = {
113
117
  }
114
118
 
115
119
  export class ObservableArrayAdministration
116
- implements IInterceptable<IArrayWillChange<any> | IArrayWillSplice<any>>, IListenable {
120
+ implements IInterceptable<IArrayWillChange<any> | IArrayWillSplice<any>>, IListenable
121
+ {
117
122
  atom_: IAtom
118
123
  readonly values_: any[] = [] // this is the prop that gets proxied, so can't replace it!
119
124
  interceptors_
@@ -135,13 +140,16 @@ export class ObservableArrayAdministration
135
140
  }
136
141
 
137
142
  dehanceValue_(value: any): any {
138
- if (this.dehancer !== undefined) return this.dehancer(value)
143
+ if (this.dehancer !== undefined) {
144
+ return this.dehancer(value)
145
+ }
139
146
  return value
140
147
  }
141
148
 
142
149
  dehanceValues_(values: any[]): any[] {
143
- if (this.dehancer !== undefined && values.length > 0)
150
+ if (this.dehancer !== undefined && values.length > 0) {
144
151
  return values.map(this.dehancer) as any
152
+ }
145
153
  return values
146
154
  }
147
155
 
@@ -175,35 +183,56 @@ export class ObservableArrayAdministration
175
183
  }
176
184
 
177
185
  setArrayLength_(newLength: number) {
178
- if (typeof newLength !== "number" || newLength < 0) die("Out of range: " + newLength)
186
+ if (typeof newLength !== "number" || isNaN(newLength) || newLength < 0) {
187
+ die("Out of range: " + newLength)
188
+ }
179
189
  let currentLength = this.values_.length
180
- if (newLength === currentLength) return
181
- else if (newLength > currentLength) {
190
+ if (newLength === currentLength) {
191
+ return
192
+ } else if (newLength > currentLength) {
182
193
  const newItems = new Array(newLength - currentLength)
183
- for (let i = 0; i < newLength - currentLength; i++) newItems[i] = undefined // No Array.fill everywhere...
194
+ for (let i = 0; i < newLength - currentLength; i++) {
195
+ newItems[i] = undefined
196
+ } // No Array.fill everywhere...
184
197
  this.spliceWithArray_(currentLength, 0, newItems)
185
- } else this.spliceWithArray_(newLength, currentLength - newLength)
198
+ } else {
199
+ this.spliceWithArray_(newLength, currentLength - newLength)
200
+ }
186
201
  }
187
202
 
188
203
  updateArrayLength_(oldLength: number, delta: number) {
189
- if (oldLength !== this.lastKnownLength_) die(16)
204
+ if (oldLength !== this.lastKnownLength_) {
205
+ die(16)
206
+ }
190
207
  this.lastKnownLength_ += delta
191
- if (this.legacyMode_ && delta > 0) reserveArrayBuffer(oldLength + delta + 1)
208
+ if (this.legacyMode_ && delta > 0) {
209
+ reserveArrayBuffer(oldLength + delta + 1)
210
+ }
192
211
  }
193
212
 
194
213
  spliceWithArray_(index: number, deleteCount?: number, newItems?: any[]): any[] {
195
214
  checkIfStateModificationsAreAllowed(this.atom_)
196
215
  const length = this.values_.length
197
216
 
198
- if (index === undefined) index = 0
199
- else if (index > length) index = length
200
- else if (index < 0) index = Math.max(0, length + index)
217
+ if (index === undefined) {
218
+ index = 0
219
+ } else if (index > length) {
220
+ index = length
221
+ } else if (index < 0) {
222
+ index = Math.max(0, length + index)
223
+ }
201
224
 
202
- if (arguments.length === 1) deleteCount = length - index
203
- else if (deleteCount === undefined || deleteCount === null) deleteCount = 0
204
- else deleteCount = Math.max(0, Math.min(deleteCount, length - index))
225
+ if (arguments.length === 1) {
226
+ deleteCount = length - index
227
+ } else if (deleteCount === undefined || deleteCount === null) {
228
+ deleteCount = 0
229
+ } else {
230
+ deleteCount = Math.max(0, Math.min(deleteCount, length - index))
231
+ }
205
232
 
206
- if (newItems === undefined) newItems = EMPTY_ARRAY
233
+ if (newItems === undefined) {
234
+ newItems = EMPTY_ARRAY
235
+ }
207
236
 
208
237
  if (hasInterceptors(this)) {
209
238
  const change = interceptChange<IArrayWillSplice<any>>(this as any, {
@@ -213,7 +242,9 @@ export class ObservableArrayAdministration
213
242
  removedCount: deleteCount,
214
243
  added: newItems
215
244
  })
216
- if (!change) return EMPTY_ARRAY
245
+ if (!change) {
246
+ return EMPTY_ARRAY
247
+ }
217
248
  deleteCount = change.removedCount
218
249
  newItems = change.added
219
250
  }
@@ -226,8 +257,9 @@ export class ObservableArrayAdministration
226
257
  }
227
258
  const res = this.spliceItemsIntoValues_(index, deleteCount, newItems)
228
259
 
229
- if (deleteCount !== 0 || newItems.length !== 0)
260
+ if (deleteCount !== 0 || newItems.length !== 0) {
230
261
  this.notifyArraySplice_(index, newItems, res)
262
+ }
231
263
  return this.dehanceValues_(res)
232
264
  }
233
265
 
@@ -235,12 +267,18 @@ export class ObservableArrayAdministration
235
267
  if (newItems.length < MAX_SPLICE_SIZE) {
236
268
  return this.values_.splice(index, deleteCount, ...newItems)
237
269
  } else {
270
+ // The items removed by the splice
238
271
  const res = this.values_.slice(index, index + deleteCount)
272
+ // The items that that should remain at the end of the array
239
273
  let oldItems = this.values_.slice(index + deleteCount)
240
- this.values_.length = index + newItems.length - deleteCount
241
- for (let i = 0; i < newItems.length; i++) this.values_[index + i] = newItems[i]
242
- for (let i = 0; i < oldItems.length; i++)
274
+ // New length is the previous length + addition count - deletion count
275
+ this.values_.length += newItems.length - deleteCount
276
+ for (let i = 0; i < newItems.length; i++) {
277
+ this.values_[index + i] = newItems[i]
278
+ }
279
+ for (let i = 0; i < oldItems.length; i++) {
243
280
  this.values_[index + newItems.length + i] = oldItems[i]
281
+ }
244
282
  return res
245
283
  }
246
284
  }
@@ -263,10 +301,16 @@ export class ObservableArrayAdministration
263
301
 
264
302
  // The reason why this is on right hand side here (and not above), is this way the uglifier will drop it, but it won't
265
303
  // cause any runtime overhead in development mode without NODE_ENV set, unless spying is enabled
266
- if (__DEV__ && notifySpy) spyReportStart(change!)
304
+ if (__DEV__ && notifySpy) {
305
+ spyReportStart(change!)
306
+ }
267
307
  this.atom_.reportChanged()
268
- if (notify) notifyListeners(this, change)
269
- if (__DEV__ && notifySpy) spyReportEnd()
308
+ if (notify) {
309
+ notifyListeners(this, change)
310
+ }
311
+ if (__DEV__ && notifySpy) {
312
+ spyReportEnd()
313
+ }
270
314
  }
271
315
 
272
316
  notifyArraySplice_(index: number, added: any[], removed: any[]) {
@@ -287,27 +331,38 @@ export class ObservableArrayAdministration
287
331
  } as const)
288
332
  : null
289
333
 
290
- if (__DEV__ && notifySpy) spyReportStart(change!)
334
+ if (__DEV__ && notifySpy) {
335
+ spyReportStart(change!)
336
+ }
291
337
  this.atom_.reportChanged()
292
338
  // conform: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/observe
293
- if (notify) notifyListeners(this, change)
294
- if (__DEV__ && notifySpy) spyReportEnd()
339
+ if (notify) {
340
+ notifyListeners(this, change)
341
+ }
342
+ if (__DEV__ && notifySpy) {
343
+ spyReportEnd()
344
+ }
295
345
  }
296
346
 
297
347
  get_(index: number): any | undefined {
298
- if (index < this.values_.length) {
299
- this.atom_.reportObserved()
300
- return this.dehanceValue_(this.values_[index])
301
- }
302
- console.warn(
303
- __DEV__
304
- ? `[mobx] Out of bounds read: ${index}`
305
- : `[mobx.array] Attempt to read an array index (${index}) that is out of bounds (${this.values_.length}). Please check length first. Out of bound indices will not be tracked by MobX`
306
- )
348
+ if (this.legacyMode_ && index >= this.values_.length) {
349
+ console.warn(
350
+ __DEV__
351
+ ? `[mobx.array] Attempt to read an array index (${index}) that is out of bounds (${this.values_.length}). Please check length first. Out of bound indices will not be tracked by MobX`
352
+ : `[mobx] Out of bounds read: ${index}`
353
+ )
354
+ return undefined
355
+ }
356
+ this.atom_.reportObserved()
357
+ return this.dehanceValue_(this.values_[index])
307
358
  }
308
359
 
309
360
  set_(index: number, newValue: any) {
310
361
  const values = this.values_
362
+ if (this.legacyMode_ && index > values.length) {
363
+ // out of bounds
364
+ die(17, index, values.length)
365
+ }
311
366
  if (index < values.length) {
312
367
  // update at index in range
313
368
  checkIfStateModificationsAreAllowed(this.atom_)
@@ -319,7 +374,9 @@ export class ObservableArrayAdministration
319
374
  index,
320
375
  newValue
321
376
  })
322
- if (!change) return
377
+ if (!change) {
378
+ return
379
+ }
323
380
  newValue = change.newValue
324
381
  }
325
382
  newValue = this.enhancer_(newValue, oldValue)
@@ -328,12 +385,16 @@ export class ObservableArrayAdministration
328
385
  values[index] = newValue
329
386
  this.notifyArrayChildUpdate_(index, newValue, oldValue)
330
387
  }
331
- } else if (index === values.length) {
332
- // add a new item
333
- this.spliceWithArray_(index, 0, [newValue])
334
388
  } else {
335
- // out of bounds
336
- die(17, index, values.length)
389
+ // For out of bound index, we don't create an actual sparse array,
390
+ // but rather fill the holes with undefined (same as setArrayLength_).
391
+ // This could be considered a bug.
392
+ const newItems = new Array(index + 1 - values.length)
393
+ for (let i = 0; i < newItems.length - 1; i++) {
394
+ newItems[i] = undefined
395
+ } // No Array.fill everywhere...
396
+ newItems[newItems.length - 1] = newValue
397
+ this.spliceWithArray_(values.length, 0, newItems)
337
398
  }
338
399
  }
339
400
  }
@@ -33,7 +33,9 @@ import {
33
33
  die,
34
34
  isFunction,
35
35
  UPDATE,
36
- IAtom
36
+ IAtom,
37
+ PureSpyEvent,
38
+ allowStateChanges
37
39
  } from "../internal"
38
40
 
39
41
  export interface IKeyValueMap<V = any> {
@@ -41,7 +43,9 @@ export interface IKeyValueMap<V = any> {
41
43
  }
42
44
 
43
45
  export type IMapEntry<K = any, V = any> = [K, V]
46
+ export type IReadonlyMapEntry<K = any, V = any> = readonly [K, V]
44
47
  export type IMapEntries<K = any, V = any> = IMapEntry<K, V>[]
48
+ export type IReadonlyMapEntries<K = any, V = any> = IReadonlyMapEntry<K, V>[]
45
49
 
46
50
  export type IMapDidChange<K = any, V = any> = { observableKind: "map"; debugObjectName: string } & (
47
51
  | {
@@ -79,6 +83,7 @@ export const DELETE = "delete"
79
83
 
80
84
  export type IObservableMapInitialValues<K = any, V = any> =
81
85
  | IMapEntries<K, V>
86
+ | IReadonlyMapEntries<K, V>
82
87
  | IKeyValueMap<V>
83
88
  | Map<K, V>
84
89
 
@@ -105,7 +110,9 @@ export class ObservableMap<K = any, V = any>
105
110
  this.keysAtom_ = createAtom(__DEV__ ? `${this.name_}.keys()` : "ObservableMap.keys()")
106
111
  this.data_ = new Map()
107
112
  this.hasMap_ = new Map()
108
- this.merge(initialData)
113
+ allowStateChanges(true, () => {
114
+ this.merge(initialData)
115
+ })
109
116
  }
110
117
 
111
118
  private has_(key: K): boolean {
@@ -113,7 +120,9 @@ export class ObservableMap<K = any, V = any>
113
120
  }
114
121
 
115
122
  has(key: K): boolean {
116
- if (!globalState.trackingDerivation) return this.has_(key)
123
+ if (!globalState.trackingDerivation) {
124
+ return this.has_(key)
125
+ }
117
126
 
118
127
  let entry = this.hasMap_.get(key)
119
128
  if (!entry) {
@@ -139,7 +148,9 @@ export class ObservableMap<K = any, V = any>
139
148
  newValue: value,
140
149
  name: key
141
150
  })
142
- if (!change) return this
151
+ if (!change) {
152
+ return this
153
+ }
143
154
  value = change.newValue!
144
155
  }
145
156
  if (hasKey) {
@@ -158,7 +169,9 @@ export class ObservableMap<K = any, V = any>
158
169
  object: this,
159
170
  name: key
160
171
  })
161
- if (!change) return false
172
+ if (!change) {
173
+ return false
174
+ }
162
175
  }
163
176
  if (this.has_(key)) {
164
177
  const notifySpy = isSpyEnabled()
@@ -175,28 +188,27 @@ export class ObservableMap<K = any, V = any>
175
188
  }
176
189
  : null
177
190
 
178
- if (__DEV__ && notifySpy) spyReportStart(change!)
191
+ if (__DEV__ && notifySpy) {
192
+ spyReportStart(change! as PureSpyEvent)
193
+ } // TODO fix type
179
194
  transaction(() => {
180
195
  this.keysAtom_.reportChanged()
181
- this.updateHasMapEntry_(key, false)
196
+ this.hasMap_.get(key)?.setNewValue_(false)
182
197
  const observable = this.data_.get(key)!
183
198
  observable.setNewValue_(undefined as any)
184
199
  this.data_.delete(key)
185
200
  })
186
- if (notify) notifyListeners(this, change)
187
- if (__DEV__ && notifySpy) spyReportEnd()
201
+ if (notify) {
202
+ notifyListeners(this, change)
203
+ }
204
+ if (__DEV__ && notifySpy) {
205
+ spyReportEnd()
206
+ }
188
207
  return true
189
208
  }
190
209
  return false
191
210
  }
192
211
 
193
- private updateHasMapEntry_(key: K, value: boolean) {
194
- let entry = this.hasMap_.get(key)
195
- if (entry) {
196
- entry.setNewValue_(value)
197
- }
198
- }
199
-
200
212
  private updateValue_(key: K, newValue: V | undefined) {
201
213
  const observable = this.data_.get(key)!
202
214
  newValue = (observable as any).prepareNewValue_(newValue) as V
@@ -215,10 +227,16 @@ export class ObservableMap<K = any, V = any>
215
227
  newValue
216
228
  }
217
229
  : null
218
- if (__DEV__ && notifySpy) spyReportStart(change!)
230
+ if (__DEV__ && notifySpy) {
231
+ spyReportStart(change! as PureSpyEvent)
232
+ } // TODO fix type
219
233
  observable.setNewValue_(newValue as V)
220
- if (notify) notifyListeners(this, change)
221
- if (__DEV__ && notifySpy) spyReportEnd()
234
+ if (notify) {
235
+ notifyListeners(this, change)
236
+ }
237
+ if (__DEV__ && notifySpy) {
238
+ spyReportEnd()
239
+ }
222
240
  }
223
241
  }
224
242
 
@@ -233,7 +251,7 @@ export class ObservableMap<K = any, V = any>
233
251
  )
234
252
  this.data_.set(key, observable)
235
253
  newValue = (observable as any).value_ // value might have been changed
236
- this.updateHasMapEntry_(key, true)
254
+ this.hasMap_.get(key)?.setNewValue_(true)
237
255
  this.keysAtom_.reportChanged()
238
256
  })
239
257
  const notifySpy = isSpyEnabled()
@@ -249,13 +267,21 @@ export class ObservableMap<K = any, V = any>
249
267
  newValue
250
268
  }
251
269
  : null
252
- if (__DEV__ && notifySpy) spyReportStart(change!)
253
- if (notify) notifyListeners(this, change)
254
- if (__DEV__ && notifySpy) spyReportEnd()
270
+ if (__DEV__ && notifySpy) {
271
+ spyReportStart(change! as PureSpyEvent)
272
+ } // TODO fix type
273
+ if (notify) {
274
+ notifyListeners(this, change)
275
+ }
276
+ if (__DEV__ && notifySpy) {
277
+ spyReportEnd()
278
+ }
255
279
  }
256
280
 
257
281
  get(key: K): V | undefined {
258
- if (this.has(key)) return this.dehanceValue_(this.data_.get(key)!.get())
282
+ if (this.has(key)) {
283
+ return this.dehanceValue_(this.data_.get(key)!.get())
284
+ }
259
285
  return this.dehanceValue_(undefined)
260
286
  }
261
287
 
@@ -304,24 +330,31 @@ export class ObservableMap<K = any, V = any>
304
330
  }
305
331
 
306
332
  forEach(callback: (value: V, key: K, object: Map<K, V>) => void, thisArg?) {
307
- for (const [key, value] of this) callback.call(thisArg, value, key, this)
333
+ for (const [key, value] of this) {
334
+ callback.call(thisArg, value, key, this)
335
+ }
308
336
  }
309
337
 
310
338
  /** Merge another object into this object, returns this. */
311
- merge(other: ObservableMap<K, V> | IKeyValueMap<V> | any): ObservableMap<K, V> {
339
+ merge(other?: IObservableMapInitialValues<K, V>): ObservableMap<K, V> {
312
340
  if (isObservableMap(other)) {
313
341
  other = new Map(other)
314
342
  }
315
343
  transaction(() => {
316
- if (isPlainObject(other))
344
+ if (isPlainObject(other)) {
317
345
  getPlainObjectKeys(other).forEach((key: any) =>
318
- this.set((key as any) as K, other[key])
346
+ this.set(key as K, (other as IKeyValueMap)[key])
319
347
  )
320
- else if (Array.isArray(other)) other.forEach(([key, value]) => this.set(key, value))
321
- else if (isES6Map(other)) {
322
- if (other.constructor !== Map) die(19, other)
348
+ } else if (Array.isArray(other)) {
349
+ other.forEach(([key, value]) => this.set(key, value))
350
+ } else if (isES6Map(other)) {
351
+ if (other.constructor !== Map) {
352
+ die(19, other)
353
+ }
323
354
  other.forEach((value, key) => this.set(key, value))
324
- } else if (other !== null && other !== undefined) die(20, other)
355
+ } else if (other !== null && other !== undefined) {
356
+ die(20, other)
357
+ }
325
358
  })
326
359
  return this
327
360
  }
@@ -329,12 +362,14 @@ export class ObservableMap<K = any, V = any>
329
362
  clear() {
330
363
  transaction(() => {
331
364
  untracked(() => {
332
- for (const key of this.keys()) this.delete(key)
365
+ for (const key of this.keys()) {
366
+ this.delete(key)
367
+ }
333
368
  })
334
369
  })
335
370
  }
336
371
 
337
- replace(values: ObservableMap<K, V> | IKeyValueMap<V> | any): ObservableMap<K, V> {
372
+ replace(values: IObservableMapInitialValues<K, V>): ObservableMap<K, V> {
338
373
  // Implementation requirements:
339
374
  // - respect ordering of replacement map
340
375
  // - allow interceptors to run and potentially prevent individual operations
@@ -435,8 +470,9 @@ export class ObservableMap<K = any, V = any>
435
470
  * for callback details
436
471
  */
437
472
  observe_(listener: (changes: IMapDidChange<K, V>) => void, fireImmediately?: boolean): Lambda {
438
- if (__DEV__ && fireImmediately === true)
473
+ if (__DEV__ && fireImmediately === true) {
439
474
  die("`observe` doesn't support fireImmediately=true in combination with maps.")
475
+ }
440
476
  return registerListener(this, listener)
441
477
  }
442
478