Skip to content

Commit

Permalink
fix createMutable getters do not work if they're on the prototype #1746
Browse files Browse the repository at this point in the history
  • Loading branch information
takeramagan committed Jan 12, 2024
1 parent 468187a commit 054e9b3
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 2 deletions.
20 changes: 18 additions & 2 deletions packages/solid/store/src/mutable.ts
Expand Up @@ -94,19 +94,35 @@ function wrap<T extends StoreNode>(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
});
}
}
Expand Down
81 changes: 81 additions & 0 deletions packages/solid/store/test/mutable.spec.ts
Expand Up @@ -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<number>;
}>(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]);
});
});

0 comments on commit 054e9b3

Please sign in to comment.