From c9838542323bf30836d2de46432ce2a3c4154fff Mon Sep 17 00:00:00 2001 From: Manuel Schiller Date: Mon, 3 Mar 2025 01:19:25 +0100 Subject: [PATCH] feat: add support for `shouldThrow` in RouteApi --- packages/react-router/src/fileRoute.ts | 6 +-- packages/react-router/src/route.ts | 6 +-- packages/react-router/src/useParams.tsx | 8 +++- packages/react-router/src/useSearch.tsx | 5 ++- .../react-router/tests/routeApi.test-d.tsx | 39 +++++++++++++++++++ 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/packages/react-router/src/fileRoute.ts b/packages/react-router/src/fileRoute.ts index bc8cc774841..ac14616ab92 100644 --- a/packages/react-router/src/fileRoute.ts +++ b/packages/react-router/src/fileRoute.ts @@ -204,21 +204,21 @@ export class LazyRoute { } useSearch: UseSearchRoute = (opts) => { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return useSearch({ select: opts?.select, structuralSharing: opts?.structuralSharing, + shouldThrow: opts?.shouldThrow, from: this.options.id, } as any) as any } useParams: UseParamsRoute = (opts) => { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return useParams({ select: opts?.select, structuralSharing: opts?.structuralSharing, + shouldThrow: opts?.shouldThrow, from: this.options.id, - } as any) as any + } as any) } useLoaderDeps: UseLoaderDepsRoute = (opts) => { diff --git a/packages/react-router/src/route.ts b/packages/react-router/src/route.ts index 495a2a59fe8..5a8643d764c 100644 --- a/packages/react-router/src/route.ts +++ b/packages/react-router/src/route.ts @@ -129,21 +129,21 @@ export class RouteApi { } useSearch: UseSearchRoute = (opts) => { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return useSearch({ select: opts?.select, structuralSharing: opts?.structuralSharing, + shouldThrow: opts?.shouldThrow, from: this.id, } as any) as any } useParams: UseParamsRoute = (opts) => { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return useParams({ select: opts?.select, structuralSharing: opts?.structuralSharing, + shouldThrow: opts?.shouldThrow, from: this.id, - } as any) as any + } as any) } useLoaderDeps: UseLoaderDepsRoute = (opts) => { diff --git a/packages/react-router/src/useParams.tsx b/packages/react-router/src/useParams.tsx index 96362c1a2f3..b047a70ad1e 100644 --- a/packages/react-router/src/useParams.tsx +++ b/packages/react-router/src/useParams.tsx @@ -48,17 +48,21 @@ export type UseParamsRoute = < TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown, TStructuralSharing extends boolean = boolean, + TThrow extends boolean = true, >( opts?: UseParamsBaseOptions< TRouter, TFrom, /* TStrict */ true, - /* TThrow */ true, + TThrow, TSelected, TStructuralSharing > & StructuralSharingOption, -) => UseParamsResult +) => ThrowOrOptional< + UseParamsResult, + TThrow +> export function useParams< TRouter extends AnyRouter = RegisteredRouter, diff --git a/packages/react-router/src/useSearch.tsx b/packages/react-router/src/useSearch.tsx index 3b6c86b7add..b1abfb1e48e 100644 --- a/packages/react-router/src/useSearch.tsx +++ b/packages/react-router/src/useSearch.tsx @@ -48,17 +48,18 @@ export type UseSearchRoute = < TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown, TStructuralSharing extends boolean = boolean, + TThrow extends boolean = true, >( opts?: UseSearchBaseOptions< TRouter, TFrom, /* TStrict */ true, - /* TThrow */ true, + TThrow, TSelected, TStructuralSharing > & StructuralSharingOption, -) => UseSearchResult +) => ThrowOrOptional, TThrow> export function useSearch< TRouter extends AnyRouter = RegisteredRouter, diff --git a/packages/react-router/tests/routeApi.test-d.tsx b/packages/react-router/tests/routeApi.test-d.tsx index 972be17b5e9..ecba0254c89 100644 --- a/packages/react-router/tests/routeApi.test-d.tsx +++ b/packages/react-router/tests/routeApi.test-d.tsx @@ -59,7 +59,26 @@ describe('getRouteApi', () => { expectTypeOf(invoiceRouteApi.useParams()).toEqualTypeOf<{ invoiceId: string }>() + + expectTypeOf( + invoiceRouteApi.useParams< + DefaultRouter, + /* TSelected */ unknown, + /* TStructuralSharing */ boolean, + /* TThrow */ true + >({ shouldThrow: true }), + ).toEqualTypeOf<{ invoiceId: string }>() + + expectTypeOf( + invoiceRouteApi.useParams< + DefaultRouter, + /* TSelected */ unknown, + /* TStructuralSharing */ boolean, + /* TThrow */ false + >({ shouldThrow: false }), + ).toEqualTypeOf<{ invoiceId: string } | undefined>() }) + test('useContext', () => { expectTypeOf( invoiceRouteApi.useRouteContext(), @@ -71,6 +90,26 @@ describe('getRouteApi', () => { expectTypeOf(invoiceRouteApi.useSearch()).toEqualTypeOf<{ page: number }>() + + expectTypeOf( + invoiceRouteApi.useSearch< + DefaultRouter, + /* TSelected */ unknown, + /* TStructuralSharing */ boolean, + /* TThrow */ true + >({ shouldThrow: true }), + ).toEqualTypeOf<{ + page: number + }>() + + expectTypeOf( + invoiceRouteApi.useSearch< + DefaultRouter, + /* TSelected */ unknown, + /* TStructuralSharing */ boolean, + /* TThrow */ false + >({ shouldThrow: false }), + ).toEqualTypeOf<{ page: number } | undefined>() }) test('useLoaderData', () => { expectTypeOf(invoiceRouteApi.useLoaderData()).toEqualTypeOf<{