From df74a02fe365f2415727f51f0e35b1becbd10bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Tue, 6 Feb 2024 16:15:38 +0100 Subject: [PATCH] fix(ts): `ReadonlyURLSearchParams` should extend `URLSearchParams` (#61419) ### What? Let the developer check the instance of `ReadonlyURLSearchParams` to match against `URLSearchParams` ### Why? `useSearchParams()`'s return type is `ReadonlyURLSearchParams` which implements all the methods of `URLSearchParams`, therefore its type should be extended from `URLSearchParams` as well. Deprecated methods are also implemented to throw an error, so no runtime behavior is being changed ### How? Mark the unavailable methods as `@deprecated` which will visually mark them in IDEs: ![image](https://github.com/vercel/next.js/assets/18369201/f3de2858-14ac-4021-981d-b0267610faa7) This is similar how `ReadonlyHeaders` extends `Headers`, added in: #49075 [Slack thread](https://vercel.slack.com/archives/C03KAR5DCKC/p1706628877916779) Closes NEXT-2305 --- .../next/src/client/components/navigation.ts | 56 ++++++------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/packages/next/src/client/components/navigation.ts b/packages/next/src/client/components/navigation.ts index 97f4091723a65..5a304a04b507e 100644 --- a/packages/next/src/client/components/navigation.ts +++ b/packages/next/src/client/components/navigation.ts @@ -15,55 +15,31 @@ import { clientHookInServerComponentError } from './client-hook-in-server-compon import { getSegmentValue } from './router-reducer/reducers/get-segment-value' import { PAGE_SEGMENT_KEY, DEFAULT_SEGMENT_KEY } from '../../shared/lib/segment' -const INTERNAL_URLSEARCHPARAMS_INSTANCE = Symbol( - 'internal for urlsearchparams readonly' -) - -function readonlyURLSearchParamsError() { - return new Error('ReadonlyURLSearchParams cannot be modified') -} - -export class ReadonlyURLSearchParams { - [INTERNAL_URLSEARCHPARAMS_INSTANCE]: URLSearchParams - - entries: URLSearchParams['entries'] - forEach: URLSearchParams['forEach'] - get: URLSearchParams['get'] - getAll: URLSearchParams['getAll'] - has: URLSearchParams['has'] - keys: URLSearchParams['keys'] - values: URLSearchParams['values'] - toString: URLSearchParams['toString'] - size: any | URLSearchParams['size'] - - constructor(urlSearchParams: URLSearchParams) { - this[INTERNAL_URLSEARCHPARAMS_INSTANCE] = urlSearchParams - - this.entries = urlSearchParams.entries.bind(urlSearchParams) - this.forEach = urlSearchParams.forEach.bind(urlSearchParams) - this.get = urlSearchParams.get.bind(urlSearchParams) - this.getAll = urlSearchParams.getAll.bind(urlSearchParams) - this.has = urlSearchParams.has.bind(urlSearchParams) - this.keys = urlSearchParams.keys.bind(urlSearchParams) - this.values = urlSearchParams.values.bind(urlSearchParams) - this.toString = urlSearchParams.toString.bind(urlSearchParams) - this.size = urlSearchParams.size - } - [Symbol.iterator]() { - return this[INTERNAL_URLSEARCHPARAMS_INSTANCE][Symbol.iterator]() +/** @internal */ +class ReadonlyURLSearchParamsError extends Error { + constructor() { + super( + 'Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams' + ) } +} +export class ReadonlyURLSearchParams extends URLSearchParams { + /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams */ append() { - throw readonlyURLSearchParamsError() + throw new ReadonlyURLSearchParamsError() } + /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams */ delete() { - throw readonlyURLSearchParamsError() + throw new ReadonlyURLSearchParamsError() } + /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams */ set() { - throw readonlyURLSearchParamsError() + throw new ReadonlyURLSearchParamsError() } + /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams */ sort() { - throw readonlyURLSearchParamsError() + throw new ReadonlyURLSearchParamsError() } }