@tanstack/react-router 1.79.0 → 1.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/cjs/Match.cjs +10 -11
  2. package/dist/cjs/Match.cjs.map +1 -1
  3. package/dist/cjs/Matches.cjs +8 -4
  4. package/dist/cjs/Matches.cjs.map +1 -1
  5. package/dist/cjs/Matches.d.cts +8 -9
  6. package/dist/cjs/RouterProvider.cjs.map +1 -1
  7. package/dist/cjs/RouterProvider.d.cts +3 -3
  8. package/dist/cjs/Transitioner.cjs +9 -8
  9. package/dist/cjs/Transitioner.cjs.map +1 -1
  10. package/dist/cjs/fileRoute.cjs +15 -3
  11. package/dist/cjs/fileRoute.cjs.map +1 -1
  12. package/dist/cjs/fileRoute.d.cts +12 -19
  13. package/dist/cjs/link.cjs +4 -1
  14. package/dist/cjs/link.cjs.map +1 -1
  15. package/dist/cjs/link.d.cts +1 -1
  16. package/dist/cjs/route.cjs +33 -9
  17. package/dist/cjs/route.cjs.map +1 -1
  18. package/dist/cjs/route.d.cts +20 -38
  19. package/dist/cjs/router.cjs +1 -0
  20. package/dist/cjs/router.cjs.map +1 -1
  21. package/dist/cjs/router.d.cts +17 -11
  22. package/dist/cjs/routerContext.cjs.map +1 -1
  23. package/dist/cjs/routerContext.d.cts +1 -1
  24. package/dist/cjs/structuralSharing.d.cts +12 -0
  25. package/dist/cjs/useLoaderData.cjs +4 -2
  26. package/dist/cjs/useLoaderData.cjs.map +1 -1
  27. package/dist/cjs/useLoaderData.d.cts +12 -9
  28. package/dist/cjs/useLoaderDeps.cjs +3 -2
  29. package/dist/cjs/useLoaderDeps.cjs.map +1 -1
  30. package/dist/cjs/useLoaderDeps.d.cts +12 -8
  31. package/dist/cjs/useLocation.cjs.map +1 -1
  32. package/dist/cjs/useLocation.d.cts +6 -3
  33. package/dist/cjs/useMatch.cjs +2 -1
  34. package/dist/cjs/useMatch.cjs.map +1 -1
  35. package/dist/cjs/useMatch.d.cts +10 -8
  36. package/dist/cjs/useParams.cjs +3 -1
  37. package/dist/cjs/useParams.cjs.map +1 -1
  38. package/dist/cjs/useParams.d.cts +12 -8
  39. package/dist/cjs/useRouteContext.cjs.map +1 -1
  40. package/dist/cjs/useRouteContext.d.cts +11 -8
  41. package/dist/cjs/useRouterState.cjs +18 -1
  42. package/dist/cjs/useRouterState.cjs.map +1 -1
  43. package/dist/cjs/useRouterState.d.cts +6 -3
  44. package/dist/cjs/useSearch.cjs +3 -1
  45. package/dist/cjs/useSearch.cjs.map +1 -1
  46. package/dist/cjs/useSearch.d.cts +12 -8
  47. package/dist/cjs/utils.cjs.map +1 -1
  48. package/dist/cjs/utils.d.cts +10 -4
  49. package/dist/esm/Match.js +10 -11
  50. package/dist/esm/Match.js.map +1 -1
  51. package/dist/esm/Matches.d.ts +8 -9
  52. package/dist/esm/Matches.js +8 -4
  53. package/dist/esm/Matches.js.map +1 -1
  54. package/dist/esm/RouterProvider.d.ts +3 -3
  55. package/dist/esm/RouterProvider.js.map +1 -1
  56. package/dist/esm/Transitioner.js +10 -9
  57. package/dist/esm/Transitioner.js.map +1 -1
  58. package/dist/esm/fileRoute.d.ts +12 -19
  59. package/dist/esm/fileRoute.js +15 -3
  60. package/dist/esm/fileRoute.js.map +1 -1
  61. package/dist/esm/link.d.ts +1 -1
  62. package/dist/esm/link.js +4 -1
  63. package/dist/esm/link.js.map +1 -1
  64. package/dist/esm/route.d.ts +20 -38
  65. package/dist/esm/route.js +33 -9
  66. package/dist/esm/route.js.map +1 -1
  67. package/dist/esm/router.d.ts +17 -11
  68. package/dist/esm/router.js +1 -0
  69. package/dist/esm/router.js.map +1 -1
  70. package/dist/esm/routerContext.d.ts +1 -1
  71. package/dist/esm/routerContext.js.map +1 -1
  72. package/dist/esm/structuralSharing.d.ts +12 -0
  73. package/dist/esm/useLoaderData.d.ts +12 -9
  74. package/dist/esm/useLoaderData.js +4 -2
  75. package/dist/esm/useLoaderData.js.map +1 -1
  76. package/dist/esm/useLoaderDeps.d.ts +12 -8
  77. package/dist/esm/useLoaderDeps.js +3 -2
  78. package/dist/esm/useLoaderDeps.js.map +1 -1
  79. package/dist/esm/useLocation.d.ts +6 -3
  80. package/dist/esm/useLocation.js.map +1 -1
  81. package/dist/esm/useMatch.d.ts +10 -8
  82. package/dist/esm/useMatch.js +2 -1
  83. package/dist/esm/useMatch.js.map +1 -1
  84. package/dist/esm/useParams.d.ts +12 -8
  85. package/dist/esm/useParams.js +3 -1
  86. package/dist/esm/useParams.js.map +1 -1
  87. package/dist/esm/useRouteContext.d.ts +11 -8
  88. package/dist/esm/useRouteContext.js.map +1 -1
  89. package/dist/esm/useRouterState.d.ts +6 -3
  90. package/dist/esm/useRouterState.js +18 -1
  91. package/dist/esm/useRouterState.js.map +1 -1
  92. package/dist/esm/useSearch.d.ts +12 -8
  93. package/dist/esm/useSearch.js +3 -1
  94. package/dist/esm/useSearch.js.map +1 -1
  95. package/dist/esm/utils.d.ts +10 -4
  96. package/dist/esm/utils.js.map +1 -1
  97. package/package.json +1 -1
  98. package/src/Match.tsx +6 -7
  99. package/src/Matches.tsx +52 -24
  100. package/src/RouterProvider.tsx +4 -1
  101. package/src/Transitioner.tsx +9 -10
  102. package/src/fileRoute.ts +29 -29
  103. package/src/link.tsx +6 -3
  104. package/src/route.ts +57 -101
  105. package/src/router.ts +37 -4
  106. package/src/routerContext.tsx +1 -1
  107. package/src/structuralSharing.ts +49 -0
  108. package/src/useLoaderData.tsx +76 -28
  109. package/src/useLoaderDeps.tsx +55 -20
  110. package/src/useLocation.tsx +30 -8
  111. package/src/useMatch.tsx +71 -21
  112. package/src/useParams.tsx +70 -21
  113. package/src/useRouteContext.ts +45 -23
  114. package/src/useRouterState.tsx +45 -6
  115. package/src/useSearch.tsx +69 -20
  116. package/src/utils.ts +16 -3
package/src/router.ts CHANGED
@@ -103,7 +103,7 @@ declare global {
103
103
  cleanScripts: () => void
104
104
  dehydrated?: any
105
105
  }
106
- __TSR_ROUTER_CONTEXT__?: React.Context<Router<any, any>>
106
+ __TSR_ROUTER_CONTEXT__?: React.Context<Router<any, any, any>>
107
107
  }
108
108
  }
109
109
 
@@ -111,7 +111,7 @@ export interface Register {
111
111
  // router: Router
112
112
  }
113
113
 
114
- export type AnyRouter = Router<any, any, any, any>
114
+ export type AnyRouter = Router<any, any, any, any, any>
115
115
 
116
116
  export type AnyRouterWithContext<TContext> = Router<
117
117
  AnyRouteWithContext<TContext>,
@@ -173,6 +173,7 @@ export type TrailingSlashOption = 'always' | 'never' | 'preserve'
173
173
  export interface RouterOptions<
174
174
  TRouteTree extends AnyRoute,
175
175
  TTrailingSlashOption extends TrailingSlashOption,
176
+ TDefaultStructuralSharingOption extends boolean = false,
176
177
  TDehydrated extends Record<string, any> = Record<string, any>,
177
178
  TSerializedError extends Record<string, any> = Record<string, any>,
178
179
  > {
@@ -464,6 +465,14 @@ export interface RouterOptions<
464
465
  */
465
466
  strict?: boolean
466
467
  }
468
+
469
+ /**
470
+ * Configures whether structural sharing is enabled by default for fine-grained selectors.
471
+ *
472
+ * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultstructuralsharing-property)
473
+ */
474
+ defaultStructuralSharing?: TDefaultStructuralSharingOption
475
+
467
476
  /**
468
477
  * Configures which URI characters are allowed in path params that would ordinarily be escaped by encodeURIComponent.
469
478
  *
@@ -539,12 +548,14 @@ export interface DehydratedRouter {
539
548
  export type RouterConstructorOptions<
540
549
  TRouteTree extends AnyRoute,
541
550
  TTrailingSlashOption extends TrailingSlashOption,
551
+ TDefaultStructuralSharingOption extends boolean,
542
552
  TDehydrated extends Record<string, any>,
543
553
  TSerializedError extends Record<string, any>,
544
554
  > = Omit<
545
555
  RouterOptions<
546
556
  TRouteTree,
547
557
  TTrailingSlashOption,
558
+ TDefaultStructuralSharingOption,
548
559
  TDehydrated,
549
560
  TSerializedError
550
561
  >,
@@ -636,6 +647,7 @@ export type RouterListener<TRouterEvent extends RouterEvent> = {
636
647
  export function createRouter<
637
648
  TRouteTree extends AnyRoute,
638
649
  TTrailingSlashOption extends TrailingSlashOption,
650
+ TDefaultStructuralSharingOption extends boolean,
639
651
  TDehydrated extends Record<string, any> = Record<string, any>,
640
652
  TSerializedError extends Record<string, any> = Record<string, any>,
641
653
  >(
@@ -644,6 +656,7 @@ export function createRouter<
644
656
  : RouterConstructorOptions<
645
657
  TRouteTree,
646
658
  TTrailingSlashOption,
659
+ TDefaultStructuralSharingOption,
647
660
  TDehydrated,
648
661
  TSerializedError
649
662
  >,
@@ -651,6 +664,7 @@ export function createRouter<
651
664
  return new Router<
652
665
  TRouteTree,
653
666
  TTrailingSlashOption,
667
+ TDefaultStructuralSharingOption,
654
668
  TDehydrated,
655
669
  TSerializedError
656
670
  >(options)
@@ -666,6 +680,7 @@ type MatchRoutesOpts = {
666
680
  export class Router<
667
681
  in out TRouteTree extends AnyRoute,
668
682
  in out TTrailingSlashOption extends TrailingSlashOption,
683
+ in out TDefaultStructuralSharingOption extends boolean,
669
684
  in out TDehydrated extends Record<string, any> = Record<string, any>,
670
685
  in out TSerializedError extends Record<string, any> = Record<string, any>,
671
686
  > {
@@ -703,6 +718,7 @@ export class Router<
703
718
  RouterOptions<
704
719
  TRouteTree,
705
720
  TTrailingSlashOption,
721
+ TDefaultStructuralSharingOption,
706
722
  TDehydrated,
707
723
  TSerializedError
708
724
  >,
@@ -729,6 +745,7 @@ export class Router<
729
745
  options: RouterConstructorOptions<
730
746
  TRouteTree,
731
747
  TTrailingSlashOption,
748
+ TDefaultStructuralSharingOption,
732
749
  TDehydrated,
733
750
  TSerializedError
734
751
  >,
@@ -760,6 +777,7 @@ export class Router<
760
777
  newOptions: RouterConstructorOptions<
761
778
  TRouteTree,
762
779
  TTrailingSlashOption,
780
+ TDefaultStructuralSharingOption,
763
781
  TDehydrated,
764
782
  TSerializedError
765
783
  >,
@@ -1660,6 +1678,7 @@ export class Router<
1660
1678
  }
1661
1679
  maskedNext = build(maskedDest)
1662
1680
  }
1681
+ // console.log('buildWithMatches', {foundMask, dest, maskedDest, maskedNext})
1663
1682
  }
1664
1683
 
1665
1684
  const nextMatches = this.getMatchedRoutes(next, dest)
@@ -2209,6 +2228,8 @@ export class Router<
2209
2228
  let pendingTimeout: ReturnType<typeof setTimeout>
2210
2229
 
2211
2230
  if (shouldPending) {
2231
+ console.log('### 2186 setting timeout', pendingMs)
2232
+
2212
2233
  // If we might show a pending component, we need to wait for the
2213
2234
  // pending promise to resolve before we start showing that state
2214
2235
  pendingTimeout = setTimeout(() => {
@@ -2672,7 +2693,13 @@ export class Router<
2672
2693
  TMaskTo extends string = '',
2673
2694
  >(
2674
2695
  opts: NavigateOptions<
2675
- Router<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>,
2696
+ Router<
2697
+ TRouteTree,
2698
+ TTrailingSlashOption,
2699
+ TDefaultStructuralSharingOption,
2700
+ TDehydrated,
2701
+ TSerializedError
2702
+ >,
2676
2703
  TFrom,
2677
2704
  TTo,
2678
2705
  TMaskFrom,
@@ -2746,7 +2773,13 @@ export class Router<
2746
2773
  TResolved = ResolveRelativePath<TFrom, NoInfer<TTo>>,
2747
2774
  >(
2748
2775
  location: ToOptions<
2749
- Router<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>,
2776
+ Router<
2777
+ TRouteTree,
2778
+ TTrailingSlashOption,
2779
+ TDefaultStructuralSharingOption,
2780
+ TDehydrated,
2781
+ TSerializedError
2782
+ >,
2750
2783
  TFrom,
2751
2784
  TTo
2752
2785
  >,
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react'
2
2
  import type { Router } from './router'
3
3
 
4
- const routerContext = React.createContext<Router<any, any>>(null!)
4
+ const routerContext = React.createContext<Router<any, any, any>>(null!)
5
5
 
6
6
  export function getRouterContext() {
7
7
  if (typeof document === 'undefined') {
@@ -0,0 +1,49 @@
1
+ import type { Constrain, ValidateJSON } from './utils'
2
+ import type { AnyRouter } from './router'
3
+
4
+ export type DefaultStructuralSharingEnabled<TRouter extends AnyRouter> =
5
+ boolean extends TRouter['options']['defaultStructuralSharing']
6
+ ? // for now, default to false.
7
+ // TODO in V2: default to true
8
+ false
9
+ : NonNullable<TRouter['options']['defaultStructuralSharing']>
10
+
11
+ export interface OptionalStructuralSharing<TStructuralSharing, TConstraint> {
12
+ readonly structuralSharing?:
13
+ | Constrain<TStructuralSharing, TConstraint>
14
+ | undefined
15
+ }
16
+
17
+ export interface RequiredStructuralSharing<TStructuralSharing, TConstraint> {
18
+ readonly structuralSharing: Constrain<TStructuralSharing, TConstraint>
19
+ }
20
+
21
+ export type StructuralSharingOption<
22
+ TRouter extends AnyRouter,
23
+ TSelected,
24
+ TStructuralSharing,
25
+ > = unknown extends TSelected
26
+ ? OptionalStructuralSharing<TStructuralSharing, boolean>
27
+ : unknown extends TRouter['routeTree']
28
+ ? OptionalStructuralSharing<TStructuralSharing, boolean>
29
+ : TSelected extends ValidateJSON<TSelected>
30
+ ? OptionalStructuralSharing<TStructuralSharing, boolean>
31
+ : DefaultStructuralSharingEnabled<TRouter> extends true
32
+ ? RequiredStructuralSharing<TStructuralSharing, false>
33
+ : OptionalStructuralSharing<TStructuralSharing, false>
34
+
35
+ export type StructuralSharingEnabled<
36
+ TRouter extends AnyRouter,
37
+ TStructuralSharing,
38
+ > = boolean extends TStructuralSharing
39
+ ? DefaultStructuralSharingEnabled<TRouter>
40
+ : TStructuralSharing
41
+
42
+ export type ValidateSelected<
43
+ TRouter extends AnyRouter,
44
+ TSelected,
45
+ TStructuralSharing,
46
+ > =
47
+ StructuralSharingEnabled<TRouter, TStructuralSharing> extends true
48
+ ? ValidateJSON<TSelected>
49
+ : TSelected
@@ -1,45 +1,93 @@
1
1
  import { useMatch } from './useMatch'
2
- import type { RegisteredRouter } from './router'
3
- import type { AnyRoute } from './route'
4
- import type { MakeRouteMatch } from './Matches'
5
- import type { RouteIds } from './routeInfo'
6
- import type { Constrain, StrictOrFrom } from './utils'
2
+ import type {
3
+ StructuralSharingOption,
4
+ ValidateSelected,
5
+ } from './structuralSharing'
6
+ import type { AnyRouter, RegisteredRouter } from './router'
7
+ import type { AllLoaderData, RouteById } from './routeInfo'
8
+ import type { Expand, StrictOrFrom } from './utils'
7
9
 
8
- export type UseLoaderDataOptions<
9
- TRouteTree extends AnyRoute,
10
+ export interface UseLoaderDataBaseOptions<
11
+ TRouter extends AnyRouter,
10
12
  TFrom,
11
13
  TStrict extends boolean,
12
- TRouteMatch extends MakeRouteMatch<TRouteTree, TFrom, TStrict>,
13
14
  TSelected,
14
- > = StrictOrFrom<Constrain<TFrom, RouteIds<TRouteTree>>, TStrict> & {
15
- select?: (match: Required<TRouteMatch>['loaderData']) => TSelected
15
+ TStructuralSharing,
16
+ > {
17
+ select?: (
18
+ match: ResolveLoaderData<TRouter, TFrom, TStrict>,
19
+ ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>
16
20
  }
17
21
 
22
+ export type UseLoaderDataOptions<
23
+ TRouter extends AnyRouter,
24
+ TFrom extends string | undefined,
25
+ TStrict extends boolean,
26
+ TSelected,
27
+ TStructuralSharing,
28
+ > = StrictOrFrom<TRouter, TFrom, TStrict> &
29
+ UseLoaderDataBaseOptions<
30
+ TRouter,
31
+ TFrom,
32
+ TStrict,
33
+ TSelected,
34
+ TStructuralSharing
35
+ > &
36
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>
37
+
38
+ export type ResolveLoaderData<
39
+ TRouter extends AnyRouter,
40
+ TFrom,
41
+ TStrict extends boolean,
42
+ > = TStrict extends false
43
+ ? AllLoaderData<TRouter['routeTree']>
44
+ : Expand<RouteById<TRouter['routeTree'], TFrom>['types']['loaderData']>
45
+
46
+ export type UseLoaderDataResult<
47
+ TRouter extends AnyRouter,
48
+ TFrom,
49
+ TStrict extends boolean,
50
+ TSelected,
51
+ > = unknown extends TSelected
52
+ ? ResolveLoaderData<TRouter, TFrom, TStrict>
53
+ : TSelected
54
+
55
+ export type UseLoaderDataRoute<out TId> = <
56
+ TRouter extends AnyRouter = RegisteredRouter,
57
+ TSelected = unknown,
58
+ TStructuralSharing extends boolean = boolean,
59
+ >(
60
+ opts?: UseLoaderDataBaseOptions<
61
+ TRouter,
62
+ TId,
63
+ true,
64
+ TSelected,
65
+ TStructuralSharing
66
+ > &
67
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,
68
+ ) => UseLoaderDataResult<TRouter, TId, true, TSelected>
69
+
18
70
  export function useLoaderData<
19
- TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
71
+ TRouter extends AnyRouter = RegisteredRouter,
20
72
  TFrom extends string | undefined = undefined,
21
73
  TStrict extends boolean = true,
22
- TRouteMatch extends MakeRouteMatch<
23
- TRouteTree,
24
- TFrom,
25
- TStrict
26
- > = MakeRouteMatch<TRouteTree, TFrom, TStrict>,
27
- TSelected = Required<TRouteMatch>['loaderData'],
74
+ TSelected = unknown,
75
+ TStructuralSharing extends boolean = boolean,
28
76
  >(
29
77
  opts: UseLoaderDataOptions<
30
- TRouteTree,
78
+ TRouter,
31
79
  TFrom,
32
80
  TStrict,
33
- TRouteMatch,
34
- TSelected
81
+ TSelected,
82
+ TStructuralSharing
35
83
  >,
36
- ): TSelected {
37
- return useMatch<TRouteTree, TFrom, TStrict, TRouteMatch, TSelected>({
38
- ...opts,
39
- select: (s) => {
40
- return typeof opts.select === 'function'
41
- ? opts.select(s.loaderData)
42
- : (s.loaderData as TSelected)
84
+ ): UseLoaderDataResult<TRouter, TFrom, TStrict, TSelected> {
85
+ return useMatch({
86
+ from: opts.from!,
87
+ strict: opts.strict,
88
+ structuralSharing: opts.structuralSharing,
89
+ select: (s: any) => {
90
+ return opts.select ? opts.select(s.loaderData) : s.loaderData
43
91
  },
44
- })
92
+ } as any) as UseLoaderDataResult<TRouter, TFrom, TStrict, TSelected>
45
93
  }
@@ -1,29 +1,64 @@
1
1
  import { useMatch } from './useMatch'
2
- import type { RegisteredRouter } from './router'
3
- import type { AnyRoute } from './route'
4
- import type { MakeRouteMatch } from './Matches'
5
- import type { RouteIds } from './routeInfo'
6
- import type { Constrain, StrictOrFrom } from './utils'
2
+ import type {
3
+ StructuralSharingOption,
4
+ ValidateSelected,
5
+ } from './structuralSharing'
6
+ import type { AnyRouter, RegisteredRouter } from './router'
7
+ import type { RouteById } from './routeInfo'
8
+ import type { Expand, StrictOrFrom } from './utils'
9
+
10
+ export interface UseLoaderDepsBaseOptions<
11
+ TRouter extends AnyRouter,
12
+ TFrom,
13
+ TSelected,
14
+ TStructuralSharing,
15
+ > {
16
+ select?: (
17
+ deps: ResolveLoaderDeps<TRouter, TFrom>,
18
+ ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>
19
+ }
20
+
21
+ export type UseLoaderDepsOptions<
22
+ TRouter extends AnyRouter,
23
+ TFrom extends string | undefined,
24
+ TSelected,
25
+ TStructuralSharing,
26
+ > = StrictOrFrom<TRouter, TFrom> &
27
+ UseLoaderDepsBaseOptions<TRouter, TFrom, TSelected, TStructuralSharing> &
28
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>
29
+
30
+ export type ResolveLoaderDeps<TRouter extends AnyRouter, TFrom> = Expand<
31
+ RouteById<TRouter['routeTree'], TFrom>['types']['loaderDeps']
32
+ >
33
+
34
+ export type UseLoaderDepsResult<
35
+ TRouter extends AnyRouter,
36
+ TFrom,
37
+ TSelected,
38
+ > = unknown extends TSelected ? ResolveLoaderDeps<TRouter, TFrom> : TSelected
39
+
40
+ export type UseLoaderDepsRoute<out TId> = <
41
+ TRouter extends AnyRouter = RegisteredRouter,
42
+ TSelected = unknown,
43
+ TStructuralSharing extends boolean = boolean,
44
+ >(
45
+ opts?: UseLoaderDepsBaseOptions<TRouter, TId, TSelected, TStructuralSharing> &
46
+ StructuralSharingOption<TRouter, TSelected, false>,
47
+ ) => UseLoaderDepsResult<TRouter, TId, TSelected>
7
48
 
8
49
  export function useLoaderDeps<
9
- TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
50
+ TRouter extends AnyRouter = RegisteredRouter,
10
51
  TFrom extends string | undefined = undefined,
11
- TRouteMatch extends MakeRouteMatch<TRouteTree, TFrom> = MakeRouteMatch<
12
- TRouteTree,
13
- TFrom
14
- >,
15
- TSelected = Required<TRouteMatch>['loaderDeps'],
52
+ TSelected = unknown,
53
+ TStructuralSharing extends boolean = boolean,
16
54
  >(
17
- opts: StrictOrFrom<Constrain<TFrom, RouteIds<TRouteTree>>> & {
18
- select?: (match: TRouteMatch) => TSelected
19
- },
20
- ): TSelected {
55
+ opts: UseLoaderDepsOptions<TRouter, TFrom, TSelected, TStructuralSharing>,
56
+ ): UseLoaderDepsResult<TRouter, TFrom, TSelected> {
57
+ const { select, ...rest } = opts
21
58
  return useMatch({
22
- ...opts,
59
+ ...rest,
23
60
  select: (s) => {
24
- return typeof opts.select === 'function'
25
- ? opts.select(s.loaderDeps)
26
- : s.loaderDeps
61
+ return select ? select(s.loaderDeps) : s.loaderDeps
27
62
  },
28
- })
63
+ }) as UseLoaderDepsResult<TRouter, TFrom, TSelected>
29
64
  }
@@ -1,15 +1,37 @@
1
1
  import { useRouterState } from './useRouterState'
2
+ import type {
3
+ StructuralSharingOption,
4
+ ValidateSelected,
5
+ } from './structuralSharing'
2
6
  import type { AnyRouter, RegisteredRouter, RouterState } from './router'
3
7
 
8
+ export interface UseLocationBaseOptions<
9
+ TRouter extends AnyRouter,
10
+ TSelected,
11
+ TStructuralSharing extends boolean = boolean,
12
+ > {
13
+ select?: (
14
+ state: RouterState<TRouter['routeTree']>['location'],
15
+ ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>
16
+ }
17
+
18
+ export type UseLocationResult<
19
+ TRouter extends AnyRouter,
20
+ TSelected,
21
+ > = unknown extends TSelected
22
+ ? RouterState<TRouter['routeTree']>['location']
23
+ : TSelected
24
+
4
25
  export function useLocation<
5
26
  TRouter extends AnyRouter = RegisteredRouter,
6
- TLocationState = RouterState<TRouter['routeTree']>['location'],
7
- TSelected = TLocationState,
8
- >(opts?: { select?: (state: TLocationState) => TSelected }): TSelected {
27
+ TSelected = unknown,
28
+ TStructuralSharing extends boolean = boolean,
29
+ >(
30
+ opts?: UseLocationBaseOptions<TRouter, TSelected, TStructuralSharing> &
31
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,
32
+ ): UseLocationResult<TRouter, TSelected> {
9
33
  return useRouterState({
10
- select: (state) =>
11
- opts?.select
12
- ? opts.select(state.location as TLocationState)
13
- : (state.location as TSelected),
14
- })
34
+ select: (state: any) =>
35
+ opts?.select ? opts.select(state.location) : state.location,
36
+ } as any) as UseLocationResult<TRouter, TSelected>
15
37
  }
package/src/useMatch.tsx CHANGED
@@ -2,44 +2,93 @@ import * as React from 'react'
2
2
  import invariant from 'tiny-invariant'
3
3
  import { useRouterState } from './useRouterState'
4
4
  import { matchContext } from './matchContext'
5
- import type { RegisteredRouter } from './router'
6
- import type { AnyRoute } from './route'
5
+ import type {
6
+ StructuralSharingOption,
7
+ ValidateSelected,
8
+ } from './structuralSharing'
9
+ import type { AnyRouter, RegisteredRouter } from './router'
7
10
  import type { MakeRouteMatch } from './Matches'
8
- import type { RouteIds } from './routeInfo'
9
- import type { Constrain, StrictOrFrom } from './utils'
11
+ import type { StrictOrFrom, ThrowOrOptional } from './utils'
10
12
 
11
- export type UseMatchOptions<
13
+ export interface UseMatchBaseOptions<
14
+ TRouter extends AnyRouter,
12
15
  TFrom,
13
16
  TStrict extends boolean,
14
- TRouteMatch,
17
+ TThrow,
15
18
  TSelected,
16
- TThrow extends boolean,
17
- > = StrictOrFrom<TFrom, TStrict> & {
18
- select?: (match: TRouteMatch) => TSelected
19
+ TStructuralSharing extends boolean,
20
+ > {
21
+ select?: (
22
+ match: MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>,
23
+ ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>
19
24
  shouldThrow?: TThrow
20
25
  }
21
26
 
27
+ export type UseMatchRoute<out TFrom> = <
28
+ TRouter extends AnyRouter = RegisteredRouter,
29
+ TSelected = unknown,
30
+ TStructuralSharing extends boolean = boolean,
31
+ >(
32
+ opts?: UseMatchBaseOptions<
33
+ TRouter,
34
+ TFrom,
35
+ true,
36
+ true,
37
+ TSelected,
38
+ TStructuralSharing
39
+ > &
40
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,
41
+ ) => UseMatchResult<TRouter, TFrom, true, TSelected>
42
+
43
+ export type UseMatchOptions<
44
+ TRouter extends AnyRouter,
45
+ TFrom extends string | undefined,
46
+ TStrict extends boolean,
47
+ TSelected,
48
+ TThrow extends boolean,
49
+ TStructuralSharing extends boolean,
50
+ > = StrictOrFrom<TRouter, TFrom, TStrict> &
51
+ UseMatchBaseOptions<
52
+ TRouter,
53
+ TFrom,
54
+ TStrict,
55
+ TThrow,
56
+ TSelected,
57
+ TStructuralSharing
58
+ > &
59
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>
60
+
61
+ export type UseMatchResult<
62
+ TRouter extends AnyRouter,
63
+ TFrom,
64
+ TStrict extends boolean,
65
+ TSelected,
66
+ > = unknown extends TSelected
67
+ ? MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>
68
+ : TSelected
69
+
22
70
  export function useMatch<
23
- TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
71
+ TRouter extends AnyRouter = RegisteredRouter,
24
72
  TFrom extends string | undefined = undefined,
25
73
  TStrict extends boolean = true,
26
- TRouteMatch = MakeRouteMatch<TRouteTree, TFrom, TStrict>,
27
- TSelected = TRouteMatch,
28
74
  TThrow extends boolean = true,
75
+ TSelected = unknown,
76
+ TStructuralSharing extends boolean = boolean,
29
77
  >(
30
78
  opts: UseMatchOptions<
31
- Constrain<TFrom, RouteIds<TRouteTree>>,
79
+ TRouter,
80
+ TFrom,
32
81
  TStrict,
33
- TRouteMatch,
34
82
  TSelected,
35
- TThrow
83
+ TThrow,
84
+ TStructuralSharing
36
85
  >,
37
- ): TThrow extends true ? TSelected : TSelected | undefined {
86
+ ): ThrowOrOptional<UseMatchResult<TRouter, TFrom, TStrict, TSelected>, TThrow> {
38
87
  const nearestMatchId = React.useContext(matchContext)
39
88
 
40
89
  const matchSelection = useRouterState({
41
- select: (state) => {
42
- const match = state.matches.find((d) =>
90
+ select: (state: any) => {
91
+ const match = state.matches.find((d: any) =>
43
92
  opts.from ? opts.from === d.routeId : d.id === nearestMatchId,
44
93
  )
45
94
  invariant(
@@ -51,9 +100,10 @@ export function useMatch<
51
100
  return undefined
52
101
  }
53
102
 
54
- return opts.select ? opts.select(match as any) : match
103
+ return opts.select ? opts.select(match) : match
55
104
  },
56
- })
105
+ structuralSharing: opts.structuralSharing,
106
+ } as any)
57
107
 
58
- return matchSelection as TSelected
108
+ return matchSelection as any
59
109
  }