diff --git a/packages/solid/store/src/mutable.ts b/packages/solid/store/src/mutable.ts index 63e92b93..0f853ae5 100644 --- a/packages/solid/store/src/mutable.ts +++ b/packages/solid/store/src/mutable.ts @@ -94,19 +94,35 @@ function wrap(value: T): T { Object.defineProperty(value, $PROXY, { value: (p = new Proxy(value, proxyTraps)) }); const keys = Object.keys(value), desc = Object.getOwnPropertyDescriptors(value); + + const proto = Object.getPrototypeOf(value); + const isClass = + value !== null && + typeof value === "object" && + !Array.isArray(value) && + proto !== Object.prototype; + if (isClass) { + const descriptors = Object.getOwnPropertyDescriptors(proto); + keys.push(...Object.keys(descriptors)); + Object.assign(desc, descriptors); + } + for (let i = 0, l = keys.length; i < l; i++) { const prop = keys[i]; + if (prop === "constructor") continue; if (desc[prop].get) { const get = desc[prop].get!.bind(p); Object.defineProperty(value, prop, { - get + get, + configurable: true }); } if (desc[prop].set) { const og = desc[prop].set!, set = (v: T[keyof T]) => batch(() => og.call(p, v)); Object.defineProperty(value, prop, { - set + set, + configurable: true }); } } diff --git a/packages/solid/store/test/mutable.spec.ts b/packages/solid/store/test/mutable.spec.ts index b8946dee..dd099606 100644 --- a/packages/solid/store/test/mutable.spec.ts +++ b/packages/solid/store/test/mutable.spec.ts @@ -316,3 +316,84 @@ describe("In Operator", () => { expect(access).toBe(0); }); }); + +describe("Class Operator test", () => { + test("read and set class", () => { + let access = 0; + class TestChildClass { + e = 10; + get d() { + return this.e * 2; + } + set d(v) { + this.e = v; + } + } + class TestClass { + a = 1; + get b() { + access++; + return access; + } + + set b(v: number) { + access = v; + } + + child = new TestChildClass(); + arr = new Array(1, 2, 3); + } + const store = createMutable<{ + a?: number; + b: number; + c?: number; + child: { e: number; d: number }; + arr: Array; + }>(new TestClass()); + + expect("a" in store).toBe(true); + expect("b" in store).toBe(true); + expect("c" in store).toBe(false); + expect(access).toBe(0); + + const [a, b, c] = createRoot(() => { + return [ + createMemo(() => "a" in store), + createMemo(() => "b" in store), + createMemo(() => "c" in store) + ]; + }); + + expect(a()).toBe(true); + expect(b()).toBe(true); + expect(c()).toBe(false); + expect(access).toBe(0); + + store.c = 3; + + expect(a()).toBe(true); + expect(b()).toBe(true); + expect(c()).toBe(true); + expect(access).toBe(0); + + delete store.a; + expect(a()).toBe(false); + expect(b()).toBe(true); + expect(c()).toBe(true); + expect(access).toBe(0); + + expect("a" in store).toBe(false); + expect("b" in store).toBe(true); + expect("c" in store).toBe(true); + expect(access).toBe(0); + + store.b = 10; + expect(access).toBe(10); + expect(store.child.d).toBe(20); + store.child.d = 20; + expect(store.child.e).toBe(20); + expect(store.child.d).toBe(40); + store.arr.push(123); + expect(store.arr).toEqual([1, 2, 3, 123]); + }); +});