Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/makepersisted-type-inference-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solid-primitives/storage": patch
---

fix: restore `makePersisted` generic type inference under TypeScript 5+/7. Calling `makePersisted(createSignal("hello"), { name, storage: localStorage })` previously fell back to `T = unknown` and errored with `TS2769`. The public overloads now extract `T` from `S` via `SignalType<S>` (as in 4.3.5).
22 changes: 13 additions & 9 deletions packages/storage/src/persisted.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ export type PersistenceOptions<T, O extends Record<string, any> | undefined> = {
storageOptions?: O;
});

export type SignalInput = Signal<any> | [Store<any>, SetStoreFunction<any>];

export type SignalType<S extends SignalInput> =
S extends Signal<infer T> ? T : S extends [Store<infer T>, SetStoreFunction<infer T>] ? T : never;

export type PersistedState<S> = S & { 2: Promise<string> | string | null };

/**
Expand All @@ -92,19 +97,18 @@ export type PersistedState<S> = S & { 2: Promise<string> | string | null };
* @param {PersistenceOptions<T, O>} options - The options for persistence.
* @returns {PersistedState<T>} - The persisted signal or store.
*/
export function makePersisted<T, S extends Signal<T> | [Store<T>, SetStoreFunction<T>]>(
export function makePersisted<S extends SignalInput>(
signal: S,
options?: PersistenceOptions<T, undefined>,
options?: PersistenceOptions<SignalType<S>, undefined>,
): PersistedState<S>;
export function makePersisted<S extends SignalInput, O extends Record<string, any>>(
signal: S,
options: PersistenceOptions<SignalType<S>, O>,
): PersistedState<S>;
export function makePersisted<
T,
S extends Signal<T> | [Store<T>, SetStoreFunction<T>],
O extends Record<string, any>,
>(signal: S, options: PersistenceOptions<T, O>): PersistedState<S>;
export function makePersisted<
T,
S extends Signal<T> | [Store<T>, SetStoreFunction<T>],
S extends SignalInput,
O extends Record<string, any> | undefined,
T = SignalType<S>,
>(
signal: S,
options: PersistenceOptions<T, O> = {} as PersistenceOptions<T, O>,
Expand Down
12 changes: 12 additions & 0 deletions packages/storage/test/persisted.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,16 @@ describe("makePersisted", () => {
});
expect(init).toBe(promise);
});
it("infers the signal value type from the input without explicit annotations", () => {
// Regression test for solid-primitives#1000: under TypeScript 5+/7 the
// overloads previously defaulted T to `unknown` instead of inferring it
// from the input signal/store, breaking inference at the call site.
const [thing, setThing] = makePersisted(createSignal("hello"), {
name: "thing",
storage: mockStorage,
});
const _a: string = thing();
const _b: string = setThing("world");
expect(thing()).toBe("world");
});
});