From d2dd48f38d3e783a0a8cd562b898d7166bbe3f64 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 24 Jul 2023 10:31:20 +0200 Subject: [PATCH 01/13] Initial shallow implementation --- packages/deepsignal/core/src/index.ts | 19 ++++- packages/deepsignal/core/test/index.test.tsx | 74 +++++++++++++++++++- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/packages/deepsignal/core/src/index.ts b/packages/deepsignal/core/src/index.ts index ae9e7bb..cfa268d 100644 --- a/packages/deepsignal/core/src/index.ts +++ b/packages/deepsignal/core/src/index.ts @@ -3,7 +3,7 @@ import { computed, signal, Signal } from "@preact/signals-core"; const proxyToSignals = new WeakMap(); const objToProxy = new WeakMap(); const arrayToArrayOfSignals = new WeakMap(); -const proxies = new WeakSet(); +const ignore = new WeakSet(); const objToIterable = new WeakMap(); const rg = /^\$/; let peeking = false; @@ -30,9 +30,22 @@ export const peek = < return value as RevertDeepSignal[K]>; }; +export function shallow(obj: T): T; + +export function shallow< + T extends DeepSignalObject, + K extends keyof RevertDeepSignalObject +>(obj: T, key: K): RevertDeepSignal[K]>; + +export function shallow(obj: any, key?: any): any { + const o = key ? peek(obj, key) : obj; + ignore.add(o); + return o; +} + const createProxy = (target: object, handlers: ProxyHandler) => { const proxy = new Proxy(target, handlers); - proxies.add(proxy); + ignore.add(proxy); return proxy; }; @@ -140,7 +153,7 @@ const shouldProxy = (val: any): boolean => { typeof val.constructor === "function" && val.constructor.name in globalThis && (globalThis as any)[val.constructor.name] === val.constructor; - return (!isBuiltIn || supported.has(val.constructor)) && !proxies.has(val); + return (!isBuiltIn || supported.has(val.constructor)) && !ignore.has(val); }; /** TYPES **/ diff --git a/packages/deepsignal/core/test/index.test.tsx b/packages/deepsignal/core/test/index.test.tsx index a39f17d..84764cf 100644 --- a/packages/deepsignal/core/test/index.test.tsx +++ b/packages/deepsignal/core/test/index.test.tsx @@ -1,5 +1,5 @@ import { Signal, effect, signal } from "@preact/signals-core"; -import { deepSignal, peek } from "deepsignal/core"; +import { deepSignal, peek, shallow } from "deepsignal/core"; import type { RevertDeepSignal } from "deepsignal/core"; type Store = { @@ -965,4 +965,76 @@ describe("deepsignal/core", () => { expect(x).to.equal(undefined); }); }); + + describe("shallow", () => { + it("should not proxy shallow objects", () => { + const shallowObj1 = { a: 1 }; + let shallowObj2 = { b: 2 }; + const deepObj = { c: 3 }; + shallowObj2 = shallow(shallowObj2); + const store = deepSignal({ + shallowObj1: shallow(shallowObj1), + shallowObj2, + deepObj, + }); + expect(store.shallowObj1.a).to.equal(1); + expect(store.shallowObj2.b).to.equal(2); + expect(store.deepObj.c).to.equal(3); + expect(store.shallowObj1).to.equal(shallowObj1); + expect(store.shallowObj2).to.equal(shallowObj2); + expect(store.deepObj).to.not.equal(deepObj); + }); + + it("should not proxy shallow objects if shallow is called before access", () => { + const shallowObj1 = { a: 1 }; + const shallowObj2 = { b: 2 }; + const deepObj = { c: 3 }; + const store = deepSignal({ shallowObj1, shallowObj2, deepObj }); + shallow(shallowObj1); + shallow(store, "shallowObj2"); + expect(store.shallowObj1.a).to.equal(1); + expect(store.shallowObj2.b).to.equal(2); + expect(store.deepObj.c).to.equal(3); + expect(store.shallowObj1).to.equal(shallowObj1); + expect(store.shallowObj2).to.equal(shallowObj2); + expect(store.deepObj).to.not.equal(deepObj); + }); + + it("should not proxy shallow objects if shallow is called before access using the deepsignal", () => { + const shallowObj = { a: 1 }; + const deepObj = { b: 2 }; + const store = deepSignal({ shallowObj, deepObj }); + shallow(store, "shallowObj"); + expect(store.shallowObj.a).to.equal(1); + expect(store.deepObj.b).to.equal(2); + expect(store.shallowObj).to.equal(shallowObj); + expect(store.deepObj).to.not.equal(deepObj); + }); + + it("should observe changes in the shallow object", () => { + const obj = { a: 1 }; + const shallowObj = shallow(obj); + const store = deepSignal({ shallowObj }); + let x; + effect(() => { + x = store.shallowObj.a; + }); + expect(x).to.equal(1); + store.shallowObj = { a: 2 }; + expect(x).to.equal(2); + }); + + it("should not observe changes in the props of the shallow object", () => { + const obj = { a: 1 }; + const shallowObj = shallow(obj); + const store = deepSignal({ shallowObj }); + let x; + effect(() => { + x = store.shallowObj.a; + }); + expect(x).to.equal(1); + store.shallowObj.a = 2; + expect(x).to.equal(1); + }); + }); }); From 18a098e6671061ef5830fc89f6dee364f414573d Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 24 Jul 2023 10:33:27 +0200 Subject: [PATCH 02/13] Add changeset --- .changeset/nice-spoons-kick.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nice-spoons-kick.md diff --git a/.changeset/nice-spoons-kick.md b/.changeset/nice-spoons-kick.md new file mode 100644 index 0000000..5eeea91 --- /dev/null +++ b/.changeset/nice-spoons-kick.md @@ -0,0 +1,5 @@ +--- +"deepsignal": minor +--- + +Support storing shallow objects as part of the deepsignal with `shallow`. From e780620dbcc41901b9c77af8a15476ee8718bf93 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 24 Jul 2023 10:34:01 +0200 Subject: [PATCH 03/13] Enter pre --- .changeset/pre.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/pre.json diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000..c361fd9 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,8 @@ +{ + "mode": "pre", + "tag": "shallow", + "initialVersions": { + "deepsignal": "1.3.4" + }, + "changesets": [] +} From 97802d3a2e887a619bae43f1112ec31e0dbe20d5 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 24 Jul 2023 10:41:27 +0200 Subject: [PATCH 04/13] Update changeset --- package.json | 4 +- pnpm-lock.yaml | 206 ++++++++++++++++++++++++++----------------------- 2 files changed, 112 insertions(+), 98 deletions(-) diff --git a/package.json b/package.json index 21339d0..20b0150 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,8 @@ "@babel/preset-env": "^7.19.1", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.18.6", - "@changesets/changelog-github": "^0.4.6", - "@changesets/cli": "^2.24.2", + "@changesets/changelog-github": "^0.4.8", + "@changesets/cli": "^2.26.2", "@types/chai": "^4.3.3", "@types/mocha": "^9.1.1", "@types/node": "^18.6.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb808d4..243db43 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,11 +32,11 @@ importers: specifier: ^7.18.6 version: 7.18.6(@babel/core@7.19.1) '@changesets/changelog-github': - specifier: ^0.4.6 - version: 0.4.6 + specifier: ^0.4.8 + version: 0.4.8 '@changesets/cli': - specifier: ^2.24.2 - version: 2.24.2 + specifier: ^2.26.2 + version: 2.26.2 '@types/chai': specifier: ^4.3.3 version: 4.3.3 @@ -1486,6 +1486,13 @@ packages: regenerator-runtime: 0.13.9 dev: true + /@babel/runtime@7.22.6: + resolution: {integrity: sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.13.11 + dev: true + /@babel/template@7.18.10: resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} engines: {node: '>=6.9.0'} @@ -1549,72 +1556,72 @@ packages: to-fast-properties: 2.0.0 dev: true - /@changesets/apply-release-plan@6.0.4: - resolution: {integrity: sha512-PutV/ymf8cZMqvaLe/Lh5cP3kBQ9FZl6oGQ3qRDxWD1ML+/uH3jrCE7S7Zw7IVSXkD0lnMD+1dAX7fsOJ6ZvgA==} + /@changesets/apply-release-plan@6.1.4: + resolution: {integrity: sha512-FMpKF1fRlJyCZVYHr3CbinpZZ+6MwvOtWUuO8uo+svcATEoc1zRDcj23pAurJ2TZ/uVz1wFHH6K3NlACy0PLew==} dependencies: - '@babel/runtime': 7.18.9 - '@changesets/config': 2.1.1 + '@babel/runtime': 7.22.6 + '@changesets/config': 2.3.1 '@changesets/get-version-range-type': 0.3.2 - '@changesets/git': 1.4.1 - '@changesets/types': 5.1.0 + '@changesets/git': 2.0.0 + '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 detect-indent: 6.1.0 fs-extra: 7.0.1 lodash.startcase: 4.4.0 outdent: 0.5.0 - prettier: 1.19.1 + prettier: 2.8.8 resolve-from: 5.0.0 - semver: 5.7.1 + semver: 7.5.4 dev: true - /@changesets/assemble-release-plan@5.2.0: - resolution: {integrity: sha512-ewY24PEbSec2eKX0+KM7eyENA2hUUp6s4LF9p/iBxTtc+TX2Xbx5rZnlLKZkc8tpuQ3PZbyjLFXWhd1PP6SjCg==} + /@changesets/assemble-release-plan@5.2.4: + resolution: {integrity: sha512-xJkWX+1/CUaOUWTguXEbCDTyWJFECEhmdtbkjhn5GVBGxdP/JwaHBIU9sW3FR6gD07UwZ7ovpiPclQZs+j+mvg==} dependencies: - '@babel/runtime': 7.18.9 + '@babel/runtime': 7.22.6 '@changesets/errors': 0.1.4 - '@changesets/get-dependents-graph': 1.3.3 - '@changesets/types': 5.1.0 + '@changesets/get-dependents-graph': 1.3.6 + '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 - semver: 5.7.1 + semver: 7.5.4 dev: true - /@changesets/changelog-git@0.1.12: - resolution: {integrity: sha512-Xv2CPjTBmwjl8l4ZyQ3xrsXZMq8WafPUpEonDpTmcb24XY8keVzt7ZSCJuDz035EiqrjmDKDhODoQ6XiHudlig==} + /@changesets/changelog-git@0.1.14: + resolution: {integrity: sha512-+vRfnKtXVWsDDxGctOfzJsPhaCdXRYoe+KyWYoq5X/GqoISREiat0l3L8B0a453B2B4dfHGcZaGyowHbp9BSaA==} dependencies: - '@changesets/types': 5.1.0 + '@changesets/types': 5.2.1 dev: true - /@changesets/changelog-github@0.4.6: - resolution: {integrity: sha512-ahR/+o3OPodzfG9kucEMU/tEtBgwy6QoJiWi1sDBPme8n3WjT6pBlbhqNYpWAJKilomwfjBGY0MTUTs6r9d1RQ==} + /@changesets/changelog-github@0.4.8: + resolution: {integrity: sha512-jR1DHibkMAb5v/8ym77E4AMNWZKB5NPzw5a5Wtqm1JepAuIF+hrKp2u04NKM14oBZhHglkCfrla9uq8ORnK/dw==} dependencies: - '@changesets/get-github-info': 0.5.1 - '@changesets/types': 5.1.0 + '@changesets/get-github-info': 0.5.2 + '@changesets/types': 5.2.1 dotenv: 8.6.0 transitivePeerDependencies: - encoding dev: true - /@changesets/cli@2.24.2: - resolution: {integrity: sha512-Bya7bnxF8Sz+O25M6kseAludVsCy5nXSW9u2Lbje/XbJTyU5q/xwIiXF9aTUzVi/4jyKoKoOasx7B1/z+NJLzg==} + /@changesets/cli@2.26.2: + resolution: {integrity: sha512-dnWrJTmRR8bCHikJHl9b9HW3gXACCehz4OasrXpMp7sx97ECuBGGNjJhjPhdZNCvMy9mn4BWdplI323IbqsRig==} hasBin: true dependencies: - '@babel/runtime': 7.18.9 - '@changesets/apply-release-plan': 6.0.4 - '@changesets/assemble-release-plan': 5.2.0 - '@changesets/changelog-git': 0.1.12 - '@changesets/config': 2.1.1 + '@babel/runtime': 7.22.6 + '@changesets/apply-release-plan': 6.1.4 + '@changesets/assemble-release-plan': 5.2.4 + '@changesets/changelog-git': 0.1.14 + '@changesets/config': 2.3.1 '@changesets/errors': 0.1.4 - '@changesets/get-dependents-graph': 1.3.3 - '@changesets/get-release-plan': 3.0.13 - '@changesets/git': 1.4.1 + '@changesets/get-dependents-graph': 1.3.6 + '@changesets/get-release-plan': 3.0.17 + '@changesets/git': 2.0.0 '@changesets/logger': 0.0.5 - '@changesets/pre': 1.0.12 - '@changesets/read': 0.5.7 - '@changesets/types': 5.1.0 - '@changesets/write': 0.1.9 + '@changesets/pre': 1.0.14 + '@changesets/read': 0.5.9 + '@changesets/types': 5.2.1 + '@changesets/write': 0.2.3 '@manypkg/get-packages': 1.1.3 '@types/is-ci': 3.0.0 - '@types/semver': 6.2.3 + '@types/semver': 7.5.0 ansi-colors: 4.1.3 chalk: 2.4.2 enquirer: 2.3.6 @@ -1627,19 +1634,19 @@ packages: p-limit: 2.3.0 preferred-pm: 3.0.3 resolve-from: 5.0.0 - semver: 5.7.1 + semver: 7.5.4 spawndamnit: 2.0.0 term-size: 2.2.1 tty-table: 4.1.6 dev: true - /@changesets/config@2.1.1: - resolution: {integrity: sha512-nSRINMqHpdtBpNVT9Eh9HtmLhOwOTAeSbaqKM5pRmGfsvyaROTBXV84ujF9UsWNlV71YxFbxTbeZnwXSGQlyTw==} + /@changesets/config@2.3.1: + resolution: {integrity: sha512-PQXaJl82CfIXddUOppj4zWu+987GCw2M+eQcOepxN5s+kvnsZOwjEJO3DH9eVy+OP6Pg/KFEWdsECFEYTtbg6w==} dependencies: '@changesets/errors': 0.1.4 - '@changesets/get-dependents-graph': 1.3.3 + '@changesets/get-dependents-graph': 1.3.6 '@changesets/logger': 0.0.5 - '@changesets/types': 5.1.0 + '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 fs-extra: 7.0.1 micromatch: 4.0.5 @@ -1651,34 +1658,34 @@ packages: extendable-error: 0.1.7 dev: true - /@changesets/get-dependents-graph@1.3.3: - resolution: {integrity: sha512-h4fHEIt6X+zbxdcznt1e8QD7xgsXRAXd2qzLlyxoRDFSa6SxJrDAUyh7ZUNdhjBU4Byvp4+6acVWVgzmTy4UNQ==} + /@changesets/get-dependents-graph@1.3.6: + resolution: {integrity: sha512-Q/sLgBANmkvUm09GgRsAvEtY3p1/5OCzgBE5vX3vgb5CvW0j7CEljocx5oPXeQSNph6FXulJlXV3Re/v3K3P3Q==} dependencies: - '@changesets/types': 5.1.0 + '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 chalk: 2.4.2 fs-extra: 7.0.1 - semver: 5.7.1 + semver: 7.5.4 dev: true - /@changesets/get-github-info@0.5.1: - resolution: {integrity: sha512-w2yl3AuG+hFuEEmT6j1zDlg7GQLM/J2UxTmk0uJBMdRqHni4zXGe/vUlPfLom5KfX3cRfHc0hzGvloDPjWFNZw==} + /@changesets/get-github-info@0.5.2: + resolution: {integrity: sha512-JppheLu7S114aEs157fOZDjFqUDpm7eHdq5E8SSR0gUBTEK0cNSHsrSR5a66xs0z3RWuo46QvA3vawp8BxDHvg==} dependencies: dataloader: 1.4.0 - node-fetch: 2.6.7 + node-fetch: 2.6.12 transitivePeerDependencies: - encoding dev: true - /@changesets/get-release-plan@3.0.13: - resolution: {integrity: sha512-Zl/UN4FUzb5LwmzhO2STRijJT5nQCN4syPEs0p1HSIR+O2iVOzes+2yTLF2zGiOx8qPOsFx/GRSAvuhSzm+9ig==} + /@changesets/get-release-plan@3.0.17: + resolution: {integrity: sha512-6IwKTubNEgoOZwDontYc2x2cWXfr6IKxP3IhKeK+WjyD6y3M4Gl/jdQvBw+m/5zWILSOCAaGLu2ZF6Q+WiPniw==} dependencies: - '@babel/runtime': 7.18.9 - '@changesets/assemble-release-plan': 5.2.0 - '@changesets/config': 2.1.1 - '@changesets/pre': 1.0.12 - '@changesets/read': 0.5.7 - '@changesets/types': 5.1.0 + '@babel/runtime': 7.22.6 + '@changesets/assemble-release-plan': 5.2.4 + '@changesets/config': 2.3.1 + '@changesets/pre': 1.0.14 + '@changesets/read': 0.5.9 + '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 dev: true @@ -1686,14 +1693,15 @@ packages: resolution: {integrity: sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==} dev: true - /@changesets/git@1.4.1: - resolution: {integrity: sha512-GWwRXEqBsQ3nEYcyvY/u2xUK86EKAevSoKV/IhELoZ13caZ1A1TSak/71vyKILtzuLnFPk5mepP5HjBxr7lZ9Q==} + /@changesets/git@2.0.0: + resolution: {integrity: sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==} dependencies: - '@babel/runtime': 7.18.9 + '@babel/runtime': 7.22.6 '@changesets/errors': 0.1.4 - '@changesets/types': 5.1.0 + '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 is-subdir: 1.2.0 + micromatch: 4.0.5 spawndamnit: 2.0.0 dev: true @@ -1703,31 +1711,31 @@ packages: chalk: 2.4.2 dev: true - /@changesets/parse@0.3.14: - resolution: {integrity: sha512-SWnNVyC9vz61ueTbuxvA6b4HXcSx2iaWr2VEa37lPg1Vw+cEyQp7lOB219P7uow1xFfdtIEEsxbzXnqLAAaY8w==} + /@changesets/parse@0.3.16: + resolution: {integrity: sha512-127JKNd167ayAuBjUggZBkmDS5fIKsthnr9jr6bdnuUljroiERW7FBTDNnNVyJ4l69PzR57pk6mXQdtJyBCJKg==} dependencies: - '@changesets/types': 5.1.0 + '@changesets/types': 5.2.1 js-yaml: 3.14.1 dev: true - /@changesets/pre@1.0.12: - resolution: {integrity: sha512-RFzWYBZx56MtgMesXjxx7ymyI829/rcIw/41hvz3VJPnY8mDscN7RJyYu7Xm7vts2Fcd+SRcO0T/Ws3I1/6J7g==} + /@changesets/pre@1.0.14: + resolution: {integrity: sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==} dependencies: - '@babel/runtime': 7.18.9 + '@babel/runtime': 7.22.6 '@changesets/errors': 0.1.4 - '@changesets/types': 5.1.0 + '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 fs-extra: 7.0.1 dev: true - /@changesets/read@0.5.7: - resolution: {integrity: sha512-Iteg0ccTPpkJ+qFzY97k7qqdVE5Kz30TqPo9GibpBk2g8tcLFUqf+Qd0iXPLcyhUZpPL1U6Hia1gINHNKIKx4g==} + /@changesets/read@0.5.9: + resolution: {integrity: sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==} dependencies: - '@babel/runtime': 7.18.9 - '@changesets/git': 1.4.1 + '@babel/runtime': 7.22.6 + '@changesets/git': 2.0.0 '@changesets/logger': 0.0.5 - '@changesets/parse': 0.3.14 - '@changesets/types': 5.1.0 + '@changesets/parse': 0.3.16 + '@changesets/types': 5.2.1 chalk: 2.4.2 fs-extra: 7.0.1 p-filter: 2.1.0 @@ -1737,18 +1745,18 @@ packages: resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} dev: true - /@changesets/types@5.1.0: - resolution: {integrity: sha512-uUByGATZCdaPkaO9JkBsgGDjEvHyY2Sb0e/J23+cwxBi5h0fxpLF/HObggO/Fw8T2nxK6zDfJbPsdQt5RwYFJA==} + /@changesets/types@5.2.1: + resolution: {integrity: sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==} dev: true - /@changesets/write@0.1.9: - resolution: {integrity: sha512-E90ZrsrfJVOOQaP3Mm5Xd7uDwBAqq3z5paVEavTHKA8wxi7NAL8CmjgbGxSFuiP7ubnJA2BuHlrdE4z86voGOg==} + /@changesets/write@0.2.3: + resolution: {integrity: sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==} dependencies: - '@babel/runtime': 7.18.9 - '@changesets/types': 5.1.0 + '@babel/runtime': 7.22.6 + '@changesets/types': 5.2.1 fs-extra: 7.0.1 human-id: 1.0.2 - prettier: 1.19.1 + prettier: 2.8.8 dev: true /@esbuild/linux-loong64@0.14.54: @@ -1860,7 +1868,7 @@ packages: /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: - '@babel/runtime': 7.18.9 + '@babel/runtime': 7.22.6 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 @@ -1869,7 +1877,7 @@ packages: /@manypkg/get-packages@1.1.3: resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} dependencies: - '@babel/runtime': 7.18.9 + '@babel/runtime': 7.22.6 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -2132,8 +2140,8 @@ packages: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} dev: true - /@types/semver@6.2.3: - resolution: {integrity: sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==} + /@types/semver@7.5.0: + resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} dev: true /@types/sinon-chai@3.2.8: @@ -5231,8 +5239,8 @@ packages: path-to-regexp: 1.8.0 dev: true - /node-fetch@2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} + /node-fetch@2.6.12: + resolution: {integrity: sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==} engines: {node: 4.x || >=6.0.0} peerDependencies: encoding: ^0.1.0 @@ -5946,12 +5954,6 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier@1.19.1: - resolution: {integrity: sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==} - engines: {node: '>=4'} - hasBin: true - dev: true - /prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -6101,6 +6103,10 @@ packages: resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} dev: true + /regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: true + /regenerator-runtime@0.13.9: resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} dev: true @@ -6349,6 +6355,14 @@ packages: lru-cache: 6.0.0 dev: true + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + /serialize-javascript@4.0.0: resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} dependencies: From e6405ecce5d99d2fe25f184dd6c26710e438759a Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 24 Jul 2023 10:41:42 +0200 Subject: [PATCH 05/13] Release new version --- .changeset/pre.json | 4 +++- packages/deepsignal/CHANGELOG.md | 6 ++++++ packages/deepsignal/package.json | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index c361fd9..d3e55e0 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -4,5 +4,7 @@ "initialVersions": { "deepsignal": "1.3.4" }, - "changesets": [] + "changesets": [ + "nice-spoons-kick" + ] } diff --git a/packages/deepsignal/CHANGELOG.md b/packages/deepsignal/CHANGELOG.md index f014422..aa9769d 100644 --- a/packages/deepsignal/CHANGELOG.md +++ b/packages/deepsignal/CHANGELOG.md @@ -1,5 +1,11 @@ # deepsignal +## 1.4.0-shallow.0 + +### Minor Changes + +- [`18a098e`](https://github.com/luisherranz/deepsignal/commit/18a098e6671061ef5830fc89f6dee364f414573d) Thanks [@luisherranz](https://github.com/luisherranz)! - Support storing shallow objects as part of the deepsignal with `shallow`. + ## 1.3.4 ### Patch Changes diff --git a/packages/deepsignal/package.json b/packages/deepsignal/package.json index 133a635..357247e 100644 --- a/packages/deepsignal/package.json +++ b/packages/deepsignal/package.json @@ -1,6 +1,6 @@ { "name": "deepsignal", - "version": "1.3.4", + "version": "1.4.0-shallow.0", "license": "MIT", "description": "", "keywords": [], From b82326d1428a4b1ec0cf0effb23a596782dbcc9f Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 15 Jan 2024 09:55:42 +0100 Subject: [PATCH 06/13] Add TypeScript support --- packages/deepsignal/core/src/index.ts | 17 +++++-------- packages/deepsignal/core/test/index.test.tsx | 25 ++++---------------- packages/deepsignal/core/test/types.ts | 17 ++++++++++++- 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/packages/deepsignal/core/src/index.ts b/packages/deepsignal/core/src/index.ts index cfa268d..6c1dcbd 100644 --- a/packages/deepsignal/core/src/index.ts +++ b/packages/deepsignal/core/src/index.ts @@ -30,17 +30,10 @@ export const peek = < return value as RevertDeepSignal[K]>; }; -export function shallow(obj: T): T; - -export function shallow< - T extends DeepSignalObject, - K extends keyof RevertDeepSignalObject ->(obj: T, key: K): RevertDeepSignal[K]>; - -export function shallow(obj: any, key?: any): any { - const o = key ? peek(obj, key) : obj; - ignore.add(o); - return o; +const isShallow = Symbol("shallow"); +export function shallow(obj: T): T & { [isShallow]: true } { + ignore.add(obj); + return obj as T & { [isShallow]: true }; } const createProxy = (target: object, handlers: ProxyHandler) => { @@ -159,6 +152,8 @@ const shouldProxy = (val: any): boolean => { /** TYPES **/ export type DeepSignal = T extends Function + ? T + : T extends { [isShallow]: true } ? T : T extends Array ? DeepSignalArray diff --git a/packages/deepsignal/core/test/index.test.tsx b/packages/deepsignal/core/test/index.test.tsx index 84764cf..f6921c4 100644 --- a/packages/deepsignal/core/test/index.test.tsx +++ b/packages/deepsignal/core/test/index.test.tsx @@ -985,28 +985,13 @@ describe("deepsignal/core", () => { expect(store.deepObj).to.not.equal(deepObj); }); - it("should not proxy shallow objects if shallow is called before access", () => { - const shallowObj1 = { a: 1 }; - const shallowObj2 = { b: 2 }; - const deepObj = { c: 3 }; - const store = deepSignal({ shallowObj1, shallowObj2, deepObj }); - shallow(shallowObj1); - shallow(store, "shallowObj2"); - expect(store.shallowObj1.a).to.equal(1); - expect(store.shallowObj2.b).to.equal(2); - expect(store.deepObj.c).to.equal(3); - expect(store.shallowObj1).to.equal(shallowObj1); - expect(store.shallowObj2).to.equal(shallowObj2); - expect(store.deepObj).to.not.equal(deepObj); - }); - - it("should not proxy shallow objects if shallow is called before access using the deepsignal", () => { + it("should not proxy shallow objects if shallow is called on the reference before accessing the property", () => { const shallowObj = { a: 1 }; - const deepObj = { b: 2 }; + const deepObj = { c: 3 }; const store = deepSignal({ shallowObj, deepObj }); - shallow(store, "shallowObj"); + shallow(shallowObj); expect(store.shallowObj.a).to.equal(1); - expect(store.deepObj.b).to.equal(2); + expect(store.deepObj.c).to.equal(3); expect(store.shallowObj).to.equal(shallowObj); expect(store.deepObj).to.not.equal(deepObj); }); @@ -1020,7 +1005,7 @@ describe("deepsignal/core", () => { x = store.shallowObj.a; }); expect(x).to.equal(1); - store.shallowObj = { a: 2 }; + store.shallowObj = shallow({ a: 2 }); expect(x).to.equal(2); }); diff --git a/packages/deepsignal/core/test/types.ts b/packages/deepsignal/core/test/types.ts index b3952dc..d15e754 100644 --- a/packages/deepsignal/core/test/types.ts +++ b/packages/deepsignal/core/test/types.ts @@ -1,5 +1,5 @@ import { signal, Signal } from "@preact/signals-core"; -import { deepSignal, peek } from "../src"; +import { deepSignal, peek, shallow } from "../src"; // Arrays. const array = deepSignal([{ a: 1 }, { a: 2 }]); @@ -74,3 +74,18 @@ store2.a = a; store2.$a = a; const s5: number = store2.a!; const s6: Signal = store2.$a; + +// Shallow +const store3 = deepSignal({ + a: { b: 1 }, + c: shallow({ b: 2 }), +}); + +store3.a.$b; +// @ts-expect-error +store3.c.$b; + +store3.a = { b: 1 }; +// @ts-expect-error +store3.c = { b: 2 }; +store3.c = shallow({ b: 2 }); From b6e23db240812e8191b400a3311f3a5e5e701c01 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 15 Jan 2024 10:17:24 +0100 Subject: [PATCH 07/13] Test unshallowing --- packages/deepsignal/core/test/index.test.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/deepsignal/core/test/index.test.tsx b/packages/deepsignal/core/test/index.test.tsx index f6921c4..2cc85b0 100644 --- a/packages/deepsignal/core/test/index.test.tsx +++ b/packages/deepsignal/core/test/index.test.tsx @@ -996,7 +996,7 @@ describe("deepsignal/core", () => { expect(store.deepObj).to.not.equal(deepObj); }); - it("should observe changes in the shallow object", () => { + it("should observe changes in the shallow object if the reference changes", () => { const obj = { a: 1 }; const shallowObj = shallow(obj); const store = deepSignal({ shallowObj }); @@ -1009,6 +1009,21 @@ describe("deepsignal/core", () => { expect(x).to.equal(2); }); + it("should stop observing changes in the shallow object if the reference changes and it's not shallow anymore", () => { + const obj = { a: 1 }; + const shallowObj = shallow(obj); + const store = deepSignal<{ obj: typeof obj }>({ obj: shallowObj }); + let x; + effect(() => { + x = store.obj.a; + }); + expect(x).to.equal(1); + store.obj = { a: 2 }; + expect(x).to.equal(2); + store.obj.a = 3; + expect(x).to.equal(3); + }); + it("should not observe changes in the props of the shallow object", () => { const obj = { a: 1 }; const shallowObj = shallow(obj); From 8c7d48aa5b4894d50a29e002099d32421e65b043 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 15 Jan 2024 10:57:49 +0100 Subject: [PATCH 08/13] Add docs --- README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/README.md b/README.md index 80e58c8..15018f4 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Use [Preact signals](https://github.com/preactjs/signals) with the interface of - [`array.$[index]`](#arrayindex) - [`array.$length`](#arraylength) - [`peek(state, "prop")`](#peekstate-prop) + - [`shallow(obj)`](#shallow) - [`state.$prop = signal(value)`](#stateprop--signalvalue) - [`useDeepSignal`](#usedeepsignal) - [When do you need access to signals?](#when-do-you-need-access-to-signals) @@ -294,6 +295,54 @@ Note that you should only use `peek()` if you really need it. Reading a signal's _For primitive values, you can get away with using `store.$prop.peek()` instead of `peek(state, "prop")`. But in `deepsignal`, the underlying signals store the proxies, not the object. That means it's not safe to use `state.$prop.peek().nestedProp` if `prop` is an object. You should use `peek(state, "prop").nestedProp` instead._ +### `shallow(obj)` + +When using `deepsignal`, all nested objects and arrays are turned into deep signal objects/arrays. The `shallow` function is a utility that allows you to declare an object as shallow within the context of `deepsignal`. Shallow objects do not proxy their properties, meaning changes to their properties are not observed for reactivity. This can be useful for objects that you don't want to be reactive or when you have an object that should not trigger UI updates when changed. + +```js +import { deepSignal, shallow } from "deepsignal"; + +const shallowObj = { key: "value" }; +const store = deepSignal({ + someData: shallow(shallowObj), +}); + +// Accessing `store.someData` gives you the original object. +console.log(store.someData === shallowObj); // true + +// Mutating `store.someData` does NOT trigger reactivity. +store.someData.key = "newValue"; +// No reactive update is triggered since `someData` is shallow. +``` + +In practice, this means you can have parts of your state that are mutable and changeable without causing rerenders or effects to run. This becomes particularly useful for large datasets or configuration objects that you might want to include in your global state but do not need to be reactive. + +#### Observing reference changes + +Although properties of a shallow object are not reactive, the reference to the shallow object itself is observed. If you replace the reference of a shallow object with another reference, it will trigger reactive updates: + +```js +import { deepSignal, shallow } from "deepsignal"; + +const store = deepSignal({ + someData: shallow({ key: "value" }), +}); + +effect(() => { + console.log(store.someData.key); +}); + +// Changing the properties of `someData` does not trigger the `effect`. +store.someData.key = "changed"; +// No log output. + +// But replacing `someData` with a new object triggers the `effect` because store.someData is still tracked. +store.someData = shallow({ key: "new value" }); +// It will log 'new value'. +``` + +With `shallow`, you have control over the granularity of reactivity in your store, mixing both reactive deep structures with non-reactive shallow portions as needed. + ### `state.$prop = signal(value)` You can modify the underlying signal of an object's property doing an assignment to the `$`-prefixed name. From de9584c4acc0b0da77f4c717cf4f10b8bf06d6bf Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 15 Jan 2024 11:02:41 +0100 Subject: [PATCH 09/13] Exit pre --- .changeset/pre.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index d3e55e0..606b03e 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,5 +1,5 @@ { - "mode": "pre", + "mode": "exit", "tag": "shallow", "initialVersions": { "deepsignal": "1.3.4" From 71d8f9d79870d3269483c484c48639863e47ab22 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 15 Jan 2024 12:54:30 +0100 Subject: [PATCH 10/13] Fix anchor --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd9a768..278fe94 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Use [Preact signals](https://github.com/preactjs/signals) with the interface of - [`array.$[index]`](#arrayindex) - [`array.$length`](#arraylength) - [`peek(state, "prop")`](#peekstate-prop) - - [`shallow(obj)`](#shallow) + - [`shallow(obj)`](#shallowobj) - [`state.$prop = signal(value)`](#stateprop--signalvalue) - [`useDeepSignal`](#usedeepsignal) - [Common Patterns](#common-patterns) From d54aa54248914c1dca64f0ac4b0923c1739b1352 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 15 Jan 2024 16:22:25 +0100 Subject: [PATCH 11/13] Expose the Shallow type for manual typings --- README.md | 19 +++++++++++++++++++ packages/deepsignal/core/src/index.ts | 6 ++++-- packages/deepsignal/core/test/types.ts | 17 +++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 278fe94..5966541 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ Use [Preact signals](https://github.com/preactjs/signals) with the interface of - [TypeScript](#typescript) - [`DeepSignal`](#deepsignal-1) - [`RevertDeepSignal`](#revertdeepsignal) + - [`Shallow`](#shallow) - [License](#license) ## Features @@ -581,6 +582,24 @@ import type { RevertDeepSignal } from "deepsignal"; const values = Object.values(store as RevertDeepSignal); ``` +### Shallow + +You can use the `Shallow` type if you want to type a store that contains a shallow object. + +```ts +import type { Shallow } from "deepsignal"; + +type Store = { + obj: { a: number }; + shallowObj: { b: number }; +}; + +const store = deepSignal({ + obj: { a: 1 }, + shallowObj: shallow({ b: 2 }), +}); +``` + ## License `MIT`, see the [LICENSE](./LICENSE) file. diff --git a/packages/deepsignal/core/src/index.ts b/packages/deepsignal/core/src/index.ts index 50b1b26..c34d4b8 100644 --- a/packages/deepsignal/core/src/index.ts +++ b/packages/deepsignal/core/src/index.ts @@ -32,9 +32,9 @@ export const peek = < }; const isShallow = Symbol("shallow"); -export function shallow(obj: T): T & { [isShallow]: true } { +export function shallow(obj: T): Shallow { ignore.add(obj); - return obj as T & { [isShallow]: true }; + return obj as Shallow; } const createProxy = (target: object, handlers: ProxyHandler) => { @@ -277,6 +277,8 @@ type DeepSignalArray = DeepArray> & { $length?: Signal; }; +export type Shallow = T & { [isShallow]: true }; + export declare const useDeepSignal: (obj: T) => DeepSignal; type FilterSignals = K extends `$${infer P}` ? never : K; diff --git a/packages/deepsignal/core/test/types.ts b/packages/deepsignal/core/test/types.ts index d15e754..69f98c9 100644 --- a/packages/deepsignal/core/test/types.ts +++ b/packages/deepsignal/core/test/types.ts @@ -89,3 +89,20 @@ store3.a = { b: 1 }; // @ts-expect-error store3.c = { b: 2 }; store3.c = shallow({ b: 2 }); + +type Store4 = { + a: { b: number }; + c: Shallow<{ b: number }>; + d: Shallow<{ b: number }>; +}; + +const store4 = deepSignal({ + a: { b: 1 }, + c: shallow({ b: 2 }), + // @ts-expect-error + d: { b: 3 }, +}); + +store4.a.$b; +// @ts-expect-error +store4.c.$b; From 79cf9dff6fc4a9c997513ca2b923c5851ed1a606 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 15 Jan 2024 16:22:56 +0100 Subject: [PATCH 12/13] Improve explanation of DeepSignalt ype --- README.md | 38 ++++++++++++++++++++++---- packages/deepsignal/core/test/types.ts | 35 ++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5966541..063c764 100644 --- a/README.md +++ b/README.md @@ -560,16 +560,44 @@ DeepSignal exports two types, one to convert from a plain object/array to a `dee ### DeepSignal -You can use the `DeepSignal` type if you want to declare your type instead of inferring it. +You can use the `DeepSignal` type if you want to manually convert a type to a deep signal outside of the `deepSignal` function, but this is usually not required. + +One scenario where this could be useful is when doing external assignments. Imagine this case: + +```ts +import { deepSignal } from "deepsignal"; + +type State = { map: Record }; + +const state = deepSignal({ map: {} }); +``` + +If you want to assign a new object to `state.map`, TypeScript will complain because it expects a deep signal type, not a plain object one: + +```ts +const newMap: State["map"] = { someKey: true }; + +state.map = newMap; // This will fail because state.map expects a deep signal type. +``` + +You can use the `DeepSignal` type to convert a regular type into a deep signal one: ```ts import type { DeepSignal } from "deepsignal"; -type Store = DeepSignal<{ - counter: boolean; -}>; +const newMap: DeepSignal = { someKey: true }; + +state.map = newMap; // This is fine now. +``` + +You can also manually cast the type on the fly if you prefer: -const store = deepSignal({ counter: 0 }); +```ts +state.map = newMap as DeepSignal; +``` + +```ts +state.map = { someKey: true } as DeepSignal; ``` ### RevertDeepSignal diff --git a/packages/deepsignal/core/test/types.ts b/packages/deepsignal/core/test/types.ts index 69f98c9..a0eddcd 100644 --- a/packages/deepsignal/core/test/types.ts +++ b/packages/deepsignal/core/test/types.ts @@ -1,5 +1,6 @@ import { signal, Signal } from "@preact/signals-core"; import { deepSignal, peek, shallow } from "../src"; +import type { Shallow } from "../src"; // Arrays. const array = deepSignal([{ a: 1 }, { a: 2 }]); @@ -106,3 +107,37 @@ const store4 = deepSignal({ store4.a.$b; // @ts-expect-error store4.c.$b; + +// Manual typings +type Store5 = { + a: { b: number }; + c: { b: number }; +}; +const store5 = deepSignal({ + a: { b: 1 }, + c: { b: 1 }, +}); + +store5.a.b; +store5.a.$b; +store5.c.b; +store5.c.$b; +// @ts-expect-error +store5.d; + +type Store6 = { + [key: string]: { b: number }; +}; + +const store6 = deepSignal({ + a: { b: 1 }, + // @ts-expect-error + c: { b: "1" }, +}); + +store5.a.b; +store5.a.$b; +store5.c.b; +store5.c.$b; +// @ts-expect-error +store5.d; From 2e24d23734934de7695dfa727af9647a4d7a80c1 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Wed, 31 Jan 2024 13:46:54 +0100 Subject: [PATCH 13/13] Fix wrong stores in types --- packages/deepsignal/core/test/types.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/deepsignal/core/test/types.ts b/packages/deepsignal/core/test/types.ts index a0eddcd..71a85ca 100644 --- a/packages/deepsignal/core/test/types.ts +++ b/packages/deepsignal/core/test/types.ts @@ -124,20 +124,20 @@ store5.c.b; store5.c.$b; // @ts-expect-error store5.d; +store5.c = { b: 2 }; type Store6 = { [key: string]: { b: number }; }; -const store6 = deepSignal({ +const store6 = deepSignal({ a: { b: 1 }, - // @ts-expect-error - c: { b: "1" }, + c: { b: 1 }, }); -store5.a.b; -store5.a.$b; -store5.c.b; -store5.c.$b; -// @ts-expect-error -store5.d; +store6.a.b; +store6.a.$b; +store6.c.b; +store6.c.$b; +store6.d = { b: 2 }; +store6.d.$b;