diff --git a/src/api/become-observed.ts b/src/api/become-observed.ts index 1646991dc..8573b01a0 100644 --- a/src/api/become-observed.ts +++ b/src/api/become-observed.ts @@ -5,11 +5,17 @@ import { Lambda, ObservableMap, fail, - getAtom + getAtom, + ObservableSet } from "../internal" export function onBecomeObserved( - value: IObservable | IComputedValue | IObservableArray | ObservableMap, + value: + | IObservable + | IComputedValue + | IObservableArray + | ObservableMap + | ObservableSet, listener: Lambda ): Lambda export function onBecomeObserved( @@ -22,7 +28,12 @@ export function onBecomeObserved(thing, arg2, arg3?): Lambda { } export function onBecomeUnobserved( - value: IObservable | IComputedValue | IObservableArray | ObservableMap, + value: + | IObservable + | IComputedValue + | IObservableArray + | ObservableMap + | ObservableSet, listener: Lambda ): Lambda export function onBecomeUnobserved( diff --git a/src/api/intercept-read.ts b/src/api/intercept-read.ts index d8be9d88f..72c33dee8 100644 --- a/src/api/intercept-read.ts +++ b/src/api/intercept-read.ts @@ -8,7 +8,8 @@ import { isObservableArray, isObservableMap, isObservableObject, - isObservableValue + isObservableValue, + ObservableSet } from "../internal" export type ReadInterceptor = (value: any) => T @@ -23,6 +24,10 @@ export function interceptReads( observableMap: ObservableMap, handler: ReadInterceptor ): Lambda +export function interceptReads( + observableSet: ObservableSet, + handler: ReadInterceptor +): Lambda export function interceptReads( object: Object, property: string, diff --git a/src/api/intercept.ts b/src/api/intercept.ts index b0835785a..8775b4584 100644 --- a/src/api/intercept.ts +++ b/src/api/intercept.ts @@ -9,7 +9,9 @@ import { IValueWillChange, Lambda, ObservableMap, - getAdministration + getAdministration, + ObservableSet, + ISetWillChange } from "../internal" export function intercept( @@ -24,6 +26,10 @@ export function intercept( observableMap: ObservableMap, handler: IInterceptor> ): Lambda +export function intercept( + observableMap: ObservableSet, + handler: IInterceptor> +): Lambda export function intercept( observableMap: ObservableMap, property: K, diff --git a/src/api/observable.ts b/src/api/observable.ts index 28b83ce40..d4fc1737a 100644 --- a/src/api/observable.ts +++ b/src/api/observable.ts @@ -78,7 +78,7 @@ function getEnhancerFromOptions(options: CreateObservableOptions): IEnhancer( @@ -22,6 +24,11 @@ export function observe( listener: (change: IArrayChange | IArraySplice) => void, fireImmediately?: boolean ): Lambda +export function observe( + observableMap: ObservableSet, + listener: (change: ISetDidChange) => void, + fireImmediately?: boolean +): Lambda export function observe( observableMap: ObservableMap, listener: (change: IMapDidChange) => void, diff --git a/src/api/tojs.ts b/src/api/tojs.ts index 8c13a38de..292c56a51 100644 --- a/src/api/tojs.ts +++ b/src/api/tojs.ts @@ -3,7 +3,8 @@ import { isObservable, isObservableArray, isObservableValue, - isObservableMap + isObservableMap, + isObservableSet } from "../internal" export type ToJSOptions = { @@ -27,7 +28,7 @@ function toJSHelper(source, options: ToJSOptions, __alreadySeen: Map) if (!options.recurseEverything && !isObservable(source)) return source if (typeof source !== "object") return source - + // Directly return null if source is null if (source === null) return null @@ -53,6 +54,22 @@ function toJSHelper(source, options: ToJSOptions, __alreadySeen: Map) return res } + if (isObservableSet(source) || Object.getPrototypeOf(source) === Set.prototype) { + if (options.exportMapsAsObjects === false) { + const res = cache(__alreadySeen, source, new Set(), options) + source.forEach(value => { + res.add(toJSHelper(value, options!, __alreadySeen)) + }) + return res + } else { + const res = cache(__alreadySeen, source, [] as any[], options) + source.forEach(value => { + res.push(toJSHelper(value, options!, __alreadySeen)) + }) + return res + } + } + if (isObservableMap(source) || Object.getPrototypeOf(source) === Map.prototype) { if (options.exportMapsAsObjects === false) { const res = cache(__alreadySeen, source, new Map(), options) diff --git a/src/types/type-utils.ts b/src/types/type-utils.ts index a843375c4..04bb45a4e 100644 --- a/src/types/type-utils.ts +++ b/src/types/type-utils.ts @@ -8,7 +8,8 @@ import { isObservableArray, isObservableMap, isObservableObject, - isReaction + isReaction, + isObservableSet } from "../internal" export function getAtom(thing: any, property?: string): IDepTreeNode { @@ -21,6 +22,9 @@ export function getAtom(thing: any, property?: string): IDepTreeNode { ) return (thing as any)[$mobx].atom } + if (isObservableSet(thing)) { + return (thing as any)[$mobx] + } if (isObservableMap(thing)) { const anyThing = thing as any if (property === undefined) return anyThing._keysAtom @@ -66,7 +70,7 @@ export function getAdministration(thing: any, property?: string) { if (!thing) fail("Expecting some object") if (property !== undefined) return getAdministration(getAtom(thing, property)) if (isAtom(thing) || isComputedValue(thing) || isReaction(thing)) return thing - if (isObservableMap(thing)) return thing + if (isObservableMap(thing) || isObservableSet(thing)) return thing // Initializers run lazily when transpiling to babel, so make sure they are run... initializeInstance(thing) if (thing[$mobx]) return thing[$mobx] @@ -76,7 +80,8 @@ export function getAdministration(thing: any, property?: string) { export function getDebugName(thing: any, property?: string): string { let named if (property !== undefined) named = getAtom(thing, property) - else if (isObservableObject(thing) || isObservableMap(thing)) named = getAdministration(thing) + else if (isObservableObject(thing) || isObservableMap(thing) || isObservableSet(thing)) + named = getAdministration(thing) else named = getAtom(thing) // valid for arrays as well return named.name } diff --git a/src/utils/decorators.ts b/src/utils/decorators.ts index ab6232762..669bab987 100644 --- a/src/utils/decorators.ts +++ b/src/utils/decorators.ts @@ -102,7 +102,7 @@ export function createPropDecorator( if (quacksLikeADecorator(arguments)) { // @decorator decoratorArguments = EMPTY_ARRAY - return decorator.apply(null, arguments) + return decorator.apply(null, arguments as any) } else { // @decorator(args) decoratorArguments = Array.prototype.slice.call(arguments) diff --git a/test/base/set.js b/test/base/set.js index 1e9e7c6ed..e04647ed2 100644 --- a/test/base/set.js +++ b/test/base/set.js @@ -237,3 +237,32 @@ test("toStringTag", () => { expect(x[Symbol.toStringTag]).toBe("Set") expect(Object.prototype.toString.call(x)).toBe("[object Set]") }) + +test("getAtom", () => { + var x = set([1]) + expect(mobx.getAtom(x)).toBeTruthy() + + expect(mobx.isObservableSet(x)).toBeTruthy() + expect(mobx.isObservable(x)).toBeTruthy() +}) + +test("observe", () => { + const vals = [] + var x = set([1]) + mobx.observe(x, v => { + vals.push(v) + }) + x.add(2) + x.add(1) + expect(vals).toEqual([{ newValue: 2, object: x, type: "add" }]) +}) + +test("toJS", () => { + const x = mobx.observable({ x: 1 }) + const y = set([x, 1]) + + const z = mobx.toJS(y) + expect(z).toEqual([{ x: 1 }, 1]) + expect(z.x).not.toBe(x) + expect(mobx.isObservable(z.x)).toBeFalsy() +})