Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/remove-store-readonly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@solidjs/signals": patch
"solid-js": patch
---

Preserve the supplied type in `Store<T>` instead of adding a shallow readonly mapping.
4 changes: 2 additions & 2 deletions packages/signals/src/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import type { Refreshable } from "../core/index.js";
import { GlobalQueue } from "../core/scheduler.js";
import { storeNextLookup } from "./next/target.js";

/** A read-only view of a store's value as seen by consumers. Mutate it via the paired `StoreSetter`. */
export type Store<T> = Readonly<T>;
/** A reactive view of a store's value. Update it through the paired `StoreSetter`. */
export type Store<T> = T;
/**
* A store setter. The callback receives a writable **draft** of the store.
*
Expand Down
1 change: 0 additions & 1 deletion packages/signals/tests/store/createStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ describe("State immutability", () => {
test("Setting a property", () => {
const [state] = createStore({ name: "John" });
expect(state.name).toBe("John");
// @ts-expect-error can't write readonly property
state.name = "Jake";
expect(state.name).toBe("John");
});
Expand Down
36 changes: 34 additions & 2 deletions packages/signals/tests/store/store.type-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,40 @@ import {
const [store, setStore] = createStore({ name: "John", age: 30 });
store.name satisfies string;
store.age satisfies number;
// @ts-expect-error readonly
store.name = "Jake";
}

// ── stores preserve the supplied type ────────────────────────────────

{
const [source] = createStore([{ id: 1 }]);
const [store, setStore] = createStore(source);
setStore(draft => {
draft.push({ id: 2 });
});
store satisfies { id: number }[];
}

{
type List = { readonly id: string; items: { title: string }[] };
const [list] = createStore<List>({ id: "todos", items: [] });
const [store, setStore] = createStore({ list });
setStore(draft => {
draft.list.items = [{ title: "Review PR" }];
// @ts-expect-error User-authored readonly remains readonly through nesting.
draft.list.id = "done";
});
store satisfies { list: List };
}

{
type State = { readonly id: number; name: string };
const [store, setStore] = createStore<State>({ id: 1, name: "John" });
store satisfies State;
setStore(draft => {
draft.name = "Jane";
// @ts-expect-error User-authored readonly properties remain readonly.
draft.id = 2;
});
}

// ── createStore (projection) — seed matches return type ───────────────
Expand Down
Loading