diff --git a/README.md b/README.md index 4db0087..78b2f07 100644 --- a/README.md +++ b/README.md @@ -167,9 +167,6 @@ function MyComponent() { // can pass `searchParams` from server components const { urlState, setUrl, setState } = useUrlState({ defaultState: userState }); - // won't let you to accidently mutate state directly, requires TS - // urlState.name = 'John' // <- error - return (
st); setState((st) => ({ ...st, age: 18 })); diff --git a/packages/example-nextjs15/src/app/Form-for-test.tsx b/packages/example-nextjs15/src/app/Form-for-test.tsx index f332eca..e5f71e7 100644 --- a/packages/example-nextjs15/src/app/Form-for-test.tsx +++ b/packages/example-nextjs15/src/app/Form-for-test.tsx @@ -40,12 +40,6 @@ export const Form = ({ // Just to test ts types if (urlState?.tags?.length === 10) { - // @ts-expect-error should be readonly - urlState.age = 18; - // @ts-expect-error should be readonly - urlState.tags[0].value = { text: 'jjj', time: new Date() }; - // @ts-expect-error should be readonly - urlState.tags[0].value.text = 'jjj'; setState(urlState); setState((st) => st); setState((st) => ({ ...st, age: 18 })); diff --git a/packages/example-react-router6/src/Form-for-test.tsx b/packages/example-react-router6/src/Form-for-test.tsx index 14699f0..774e1bc 100644 --- a/packages/example-react-router6/src/Form-for-test.tsx +++ b/packages/example-react-router6/src/Form-for-test.tsx @@ -31,12 +31,6 @@ export const Form = ({ className }: { className?: string }) => { // Just to test ts types if (urlState?.tags?.length === 10) { - // @ts-expect-error should be readonly - urlState.age = 18; - // @ts-expect-error should be readonly - urlState.tags[0].value = { text: "jjj", time: new Date() }; - // @ts-expect-error should be readonly - urlState.tags[0].value.text = "jjj"; setState(urlState); setState((st) => st); setState((st) => ({ ...st, age: 18 })); diff --git a/packages/urlstate/next/useUrlState/README.md b/packages/urlstate/next/useUrlState/README.md index 6aac70f..ff06376 100644 --- a/packages/urlstate/next/useUrlState/README.md +++ b/packages/urlstate/next/useUrlState/README.md @@ -16,7 +16,8 @@ A custom React hook that manages state and synchronizes it with URL search param ### Returns: An object containing: -- `urlState: object` - The current state (readonly). + +- `urlState: object` - The current state. - `setState: Function` - Function to update the state without updating the URL. - `setUrl: Function` - Function to update both the state and the URL. diff --git a/packages/urlstate/next/useUrlState/useUrlState.ts b/packages/urlstate/next/useUrlState/useUrlState.ts index 6bced38..1cfc576 100644 --- a/packages/urlstate/next/useUrlState/useUrlState.ts +++ b/packages/urlstate/next/useUrlState/useUrlState.ts @@ -5,7 +5,6 @@ import React from "react"; import { parseSPObj } from "../../parseSPObj"; import { useUrlStateBase } from "../../useUrlStateBase"; import { - type DeepReadonly, filterUnknownParams, filterUnknownParamsClient, isSSR, @@ -115,11 +114,11 @@ export function useUrlState({ * @deprecated use `setUrl` */ updateUrl, - urlState: state as DeepReadonly, + urlState: state, /** * @deprecated use `urlState` */ - state: state as DeepReadonly, + state, getState, }; } diff --git a/packages/urlstate/react-router/useUrlState/README.md b/packages/urlstate/react-router/useUrlState/README.md index 03fdbf2..363f664 100644 --- a/packages/urlstate/react-router/useUrlState/README.md +++ b/packages/urlstate/react-router/useUrlState/README.md @@ -16,7 +16,8 @@ A custom React hook that manages state and synchronizes it with URL search param ### Returns: An object containing: -- `urlState: object` - The current state (readonly). + +- `urlState: object` - The current state. - `setState: Function` - Function to update the state without updating the URL. - `setUrl: Function` - Function to update both the state and the URL. diff --git a/packages/urlstate/react-router/useUrlState/useUrlState.ts b/packages/urlstate/react-router/useUrlState/useUrlState.ts index ff49925..24f76a9 100644 --- a/packages/urlstate/react-router/useUrlState/useUrlState.ts +++ b/packages/urlstate/react-router/useUrlState/useUrlState.ts @@ -9,7 +9,6 @@ import { parseSPObj } from "../../parseSPObj"; import { useUrlStateBase } from "../../useUrlStateBase"; import { assignValue, - type DeepReadonly, filterUnknownParams, filterUnknownParamsClient, type JSONCompatible, @@ -121,11 +120,11 @@ export function useUrlState({ * @deprecated use `setUrl` */ updateUrl, - urlState: state as DeepReadonly, + urlState: state, /** * @deprecated use `urlState` */ - state: state as DeepReadonly, + state, getState, }; } diff --git a/packages/urlstate/useSharedState/README.md b/packages/urlstate/useSharedState/README.md index 88f2ce5..76580bd 100644 --- a/packages/urlstate/useSharedState/README.md +++ b/packages/urlstate/useSharedState/README.md @@ -14,7 +14,8 @@ A custom React hook that manages shared state across components. ### Returns: An object containing: -- `state: T` - The current state (readonly). + +- `state: T` - The current state. - `getState: () => T` - Function to get the current state. - `setState: T | Partial | (T) => void` - Function to update the state. @@ -42,7 +43,7 @@ Updates the shared state. ### Parameters: -- `value: T | DeepReadonly | ((currState: T) => T)` - New state value or a function that receives the current state and returns the new state. +- `value: T | ((currState: T) => T)` - New state value or a function that receives the current state and returns the new state. ## `getState` diff --git a/packages/urlstate/useSharedState/useSharedState.ts b/packages/urlstate/useSharedState/useSharedState.ts index 62bea33..89ef9d1 100644 --- a/packages/urlstate/useSharedState/useSharedState.ts +++ b/packages/urlstate/useSharedState/useSharedState.ts @@ -2,12 +2,7 @@ import React from "react"; import { stateMap, subscribers } from "../subscribers"; import { useInsertionEffect } from "../useInsertionEffect"; -import { - type DeepReadonly, - isEqual, - isSSR, - type JSONCompatible, -} from "../utils"; +import { isEqual, isSSR, type JSONCompatible } from "../utils"; /** * Custom React hook for sharing state between unrelated components. @@ -51,7 +46,7 @@ export function useSharedState( const setState = React.useCallback( ( value: - | (Partial | Partial>) + | Partial | ((currState: typeof stateShape.current) => typeof stateShape.current), ): void => { const curr = stateMap.get(stateShape.current); diff --git a/packages/urlstate/useUrlStateBase/README.md b/packages/urlstate/useUrlStateBase/README.md index ba973c1..ef85a31 100644 --- a/packages/urlstate/useUrlStateBase/README.md +++ b/packages/urlstate/useUrlStateBase/README.md @@ -15,7 +15,8 @@ A custom React hook to create custom `useUrlState` hooks. ### Returns: An object containing: -- `state: object` - The current state (readonly). + +- `state: object` - The current state. - `getState: Function` - Function to get state. - `updateState: Function` - Function to update the state without updating the URL. - `updateUrl: Function` - Function to update both the state and the URL. diff --git a/packages/urlstate/useUrlStateBase/useUrlStateBase.ts b/packages/urlstate/useUrlStateBase/useUrlStateBase.ts index 76c9391..99b95dc 100644 --- a/packages/urlstate/useUrlStateBase/useUrlStateBase.ts +++ b/packages/urlstate/useUrlStateBase/useUrlStateBase.ts @@ -4,7 +4,6 @@ import { useInsertionEffect } from "../useInsertionEffect"; import { useSharedState } from "../useSharedState"; import { useUrlEncode } from "../useUrlEncode"; import { - type DeepReadonly, filterUnknownParamsClient, type JSONCompatible, type Router, @@ -110,7 +109,7 @@ export function useUrlStateBase( return { updateState: setState, updateUrl, - state: state as DeepReadonly, + state, getState, }; } diff --git a/packages/urlstate/utils.ts b/packages/urlstate/utils.ts index 1e7887f..8698c1b 100644 --- a/packages/urlstate/utils.ts +++ b/packages/urlstate/utils.ts @@ -49,16 +49,6 @@ export type JSONCompatible = { [prop: string]: JSON | JSON[]; }; -// Always will be some compromise between how strict checks are and readability -export type DeepReadonly = - T extends Map - ? ReadonlyMap, DeepReadonly> - : T extends Set - ? ReadonlySet> - : T extends object - ? { readonly [K in keyof T]: DeepReadonly } - : T; - export const getParams = (strOrSearchParams?: string | URLSearchParams) => new URLSearchParams( typeof strOrSearchParams === "string"