diff --git a/.changeset/hot-ties-play.md b/.changeset/hot-ties-play.md new file mode 100644 index 0000000..0bb9b65 --- /dev/null +++ b/.changeset/hot-ties-play.md @@ -0,0 +1,5 @@ +--- +"deepsignal": minor +--- + +Add support for setters. diff --git a/packages/deepsignal/core/src/index.ts b/packages/deepsignal/core/src/index.ts index ae9e7bb..f67b69a 100644 --- a/packages/deepsignal/core/src/index.ts +++ b/packages/deepsignal/core/src/index.ts @@ -6,6 +6,7 @@ const arrayToArrayOfSignals = new WeakMap(); const proxies = new WeakSet(); const objToIterable = new WeakMap(); const rg = /^\$/; +const descriptor = Object.getOwnPropertyDescriptor; let peeking = false; export const deepSignal = (obj: T): DeepSignal => { @@ -58,7 +59,7 @@ const get = const key = returnSignal ? fullKey.replace(rg, "") : fullKey; if ( !signals.has(key) && - typeof Object.getOwnPropertyDescriptor(target, key)?.get === "function" + typeof descriptor(target, key)?.get === "function" ) { signals.set( key, @@ -83,6 +84,8 @@ const get = const objectHandlers = { get: get(false), set(target: object, fullKey: string, val: any, receiver: object): boolean { + if (typeof descriptor(target, fullKey)?.set === "function") + return Reflect.set(target, fullKey, val, receiver); if (!proxyToSignals.has(receiver)) proxyToSignals.set(receiver, new Map()); const signals = proxyToSignals.get(receiver); if (fullKey[0] === "$") { diff --git a/packages/deepsignal/core/test/index.test.tsx b/packages/deepsignal/core/test/index.test.tsx index 339a433..f1b775d 100644 --- a/packages/deepsignal/core/test/index.test.tsx +++ b/packages/deepsignal/core/test/index.test.tsx @@ -189,6 +189,21 @@ describe("deepsignal/core", () => { expect(store.nested.b).to.equal(3); }); + it("should support setting values with setters", () => { + const store = deepSignal({ + counter: 1, + get double() { + return store.counter * 2; + }, + set double(val) { + store.counter = val / 2; + }, + }); + expect(store.counter).to.equal(1); + store.double = 4; + expect(store.counter).to.equal(2); + }); + it("should update array length", () => { expect(store.array.length).to.equal(2); store.array.push(4); @@ -394,6 +409,31 @@ describe("deepsignal/core", () => { }); describe("computations", () => { + it("should subscribe to values mutated with setters", () => { + const store = deepSignal({ + counter: 1, + get double() { + return store.counter * 2; + }, + set double(val) { + store.counter = val / 2; + }, + }); + let counter = 0; + let double = 0; + + effect(() => { + counter = store.counter; + double = store.double; + }); + + expect(counter).to.equal(1); + expect(double).to.equal(2); + store.double = 4; + expect(counter).to.equal(2); + expect(double).to.equal(4); + }); + it("should subscribe to changes when an item is removed from the array", () => { const store = deepSignal([0, 0, 0]); let sum = 0;