Skip to content

Commit 32511d1

Browse files
authored
perf: improve type checking performance of Route.Link (#4117)
1 parent 163aaa3 commit 32511d1

File tree

9 files changed

+74
-66
lines changed

9 files changed

+74
-66
lines changed

packages/react-router/src/link.tsx

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -465,20 +465,25 @@ export type LinkComponent<
465465
props: LinkComponentProps<TComp, TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
466466
) => React.ReactElement
467467

468-
export type LinkComponentRoute<in out TDefaultFrom extends string = string> = <
469-
TRouter extends AnyRouter = RegisteredRouter,
470-
const TTo extends string | undefined = undefined,
471-
const TMaskTo extends string = '',
472-
>(
473-
props: LinkComponentProps<
474-
'a',
475-
TRouter,
476-
TDefaultFrom,
477-
TTo,
478-
TDefaultFrom,
479-
TMaskTo
480-
>,
481-
) => React.ReactElement
468+
export interface LinkComponentRoute<
469+
in out TDefaultFrom extends string = string,
470+
> {
471+
defaultFrom: TDefaultFrom
472+
<
473+
TRouter extends AnyRouter = RegisteredRouter,
474+
const TTo extends string | undefined = undefined,
475+
const TMaskTo extends string = '',
476+
>(
477+
props: LinkComponentProps<
478+
'a',
479+
TRouter,
480+
this['defaultFrom'],
481+
TTo,
482+
this['defaultFrom'],
483+
TMaskTo
484+
>,
485+
): React.ReactElement
486+
}
482487

483488
export function createLink<const TComp>(
484489
Comp: Constrain<TComp, any, (props: CreateLinkProps) => ReactNode>,

packages/react-router/src/route.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ declare module '@tanstack/router-core' {
5353
}
5454

5555
export interface RouteExtensions<
56-
TId extends string,
57-
TFullPath extends string,
56+
in out TId extends string,
57+
in out TFullPath extends string,
5858
> {
5959
useMatch: UseMatchRoute<TId>
6060
useRouteContext: UseRouteContextRoute<TId>

packages/router-core/src/link.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ import type {
2323
MakeDifferenceOptional,
2424
NoInfer,
2525
NonNullableUpdater,
26-
PickRequired,
2726
Updater,
28-
WithoutEmpty,
2927
} from './utils'
3028
import type { ParsedLocation } from './location'
3129

@@ -469,11 +467,11 @@ type MakeRequiredParamsReducer<
469467
> =
470468
| (string extends TFrom
471469
? never
472-
: ResolveFromParams<TRouter, TParamVariant, TFrom> extends WithoutEmpty<
473-
PickRequired<
474-
ResolveRelativeToParams<TRouter, TParamVariant, TFrom, TTo>
475-
>
476-
>
470+
: ResolveFromParams<
471+
TRouter,
472+
TParamVariant,
473+
TFrom
474+
> extends ResolveRelativeToParams<TRouter, TParamVariant, TFrom, TTo>
477475
? true
478476
: never)
479477
| (ParamsReducer<TRouter, TParamVariant, TFrom, TTo> & {})

packages/router-core/src/redirect.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { NavigateOptions } from './link'
2-
import type { RoutePaths } from './routeInfo'
32
import type { AnyRouter, RegisteredRouter } from './router'
43
import type { PickAsRequired } from './utils'
54

@@ -10,9 +9,9 @@ export type AnyRedirect = Redirect<any, any, any, any, any>
109
*/
1110
export type Redirect<
1211
TRouter extends AnyRouter = RegisteredRouter,
13-
TFrom extends RoutePaths<TRouter['routeTree']> | string = '/',
14-
TTo extends string | undefined = '.',
15-
TMaskFrom extends RoutePaths<TRouter['routeTree']> | string = TFrom,
12+
TFrom extends string = string,
13+
TTo extends string | undefined = undefined,
14+
TMaskFrom extends string = TFrom,
1615
TMaskTo extends string = '.',
1716
> = {
1817
href?: string
@@ -39,9 +38,9 @@ export type Redirect<
3938

4039
export type ResolvedRedirect<
4140
TRouter extends AnyRouter = RegisteredRouter,
42-
TFrom extends RoutePaths<TRouter['routeTree']> = '/',
41+
TFrom extends string = string,
4342
TTo extends string = '',
44-
TMaskFrom extends RoutePaths<TRouter['routeTree']> = TFrom,
43+
TMaskFrom extends string = TFrom,
4544
TMaskTo extends string = '',
4645
> = PickAsRequired<
4746
Redirect<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,

packages/router-core/src/route.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,10 @@ export type ResolveFullPath<
442442
TPrefixed = RoutePrefix<TParentRoute['fullPath'], TPath>,
443443
> = TPrefixed extends RootRouteId ? '/' : TPrefixed
444444

445-
export interface RouteExtensions<TId, TFullPath> {}
445+
export interface RouteExtensions<in out TId, in out TFullPath> {
446+
id: TId
447+
fullPath: TFullPath
448+
}
446449

447450
export type RouteLazyFn<TRoute extends AnyRoute> = (
448451
lazyFn: () => Promise<LazyRoute>,
@@ -564,9 +567,7 @@ export interface Route<
564567
in out TChildren,
565568
in out TFileRouteTypes,
566569
> extends RouteExtensions<TId, TFullPath> {
567-
fullPath: TFullPath
568570
path: TPath
569-
id: TId
570571
parentRoute: TParentRoute
571572
children?: TChildren
572573
types: RouteTypes<

packages/router-core/src/router.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,15 @@ export type ControllablePromise<T = any> = Promise<T> & {
9494

9595
export type InjectedHtmlEntry = Promise<string>
9696

97-
export interface Register {
98-
// router: Router
97+
export interface DefaultRegister {
98+
router: AnyRouter
9999
}
100100

101-
export type RegisteredRouter = Register extends {
102-
router: infer TRouter extends AnyRouter
101+
export interface Register extends DefaultRegister {
102+
// router: Router
103103
}
104-
? TRouter
105-
: AnyRouter
104+
105+
export type RegisteredRouter = Register['router']
106106

107107
export type DefaultRemountDepsFn<TRouteTree extends AnyRoute> = (
108108
opts: MakeRemountDepsOptionsUnion<TRouteTree>,

packages/router-core/src/utils.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ export type DeepPartial<T> = T extends object
3737
}
3838
: T
3939

40-
export type MakeDifferenceOptional<TLeft, TRight> = Omit<
41-
TRight,
42-
keyof TLeft
43-
> & {
44-
[K in keyof TLeft & keyof TRight]?: TRight[K]
45-
}
40+
export type MakeDifferenceOptional<TLeft, TRight> = keyof TLeft &
41+
keyof TRight extends never
42+
? TRight
43+
: Omit<TRight, keyof TLeft & keyof TRight> & {
44+
[K in keyof TLeft & keyof TRight]?: TRight[K]
45+
}
4646

4747
// from https://stackoverflow.com/a/53955431
4848
// eslint-disable-next-line @typescript-eslint/naming-convention

packages/solid-router/src/link.tsx

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -522,20 +522,25 @@ export type LinkComponent<
522522
props: LinkComponentProps<TComp, TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
523523
) => Solid.JSX.Element
524524

525-
export type LinkComponentRoute<in out TDefaultFrom extends string = string> = <
526-
TRouter extends AnyRouter = RegisteredRouter,
527-
const TTo extends string | undefined = undefined,
528-
const TMaskTo extends string = '',
529-
>(
530-
props: LinkComponentProps<
531-
'a',
532-
TRouter,
533-
TDefaultFrom,
534-
TTo,
535-
TDefaultFrom,
536-
TMaskTo
537-
>,
538-
) => Solid.JSX.Element
525+
export interface LinkComponentRoute<
526+
in out TDefaultFrom extends string = string,
527+
> {
528+
defaultFrom: TDefaultFrom
529+
<
530+
TRouter extends AnyRouter = RegisteredRouter,
531+
const TTo extends string | undefined = undefined,
532+
const TMaskTo extends string = '',
533+
>(
534+
props: LinkComponentProps<
535+
'a',
536+
TRouter,
537+
this['defaultFrom'],
538+
TTo,
539+
this['defaultFrom'],
540+
TMaskTo
541+
>,
542+
): Solid.JSX.Element
543+
}
539544

540545
export function createLink<const TComp>(
541546
Comp: Constrain<TComp, any, (props: CreateLinkProps) => Solid.JSX.Element>,

packages/solid-router/src/route.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ declare module '@tanstack/router-core' {
5353
}
5454

5555
export interface RouteExtensions<
56-
TId extends string,
57-
TFullPath extends string,
56+
in out TId extends string,
57+
in out TFullPath extends string,
5858
> {
5959
useMatch: UseMatchRoute<TId>
6060
useRouteContext: UseRouteContextRoute<TId>
@@ -132,13 +132,13 @@ export class RouteApi<
132132
return notFound({ routeId: this.id as string, ...opts })
133133
}
134134

135-
Link: LinkComponentRoute<RouteTypesById<TRouter, TId>['fullPath']> = (
135+
Link: LinkComponentRoute<RouteTypesById<TRouter, TId>['fullPath']> = ((
136136
props,
137137
) => {
138138
const router = useRouter()
139139
const fullPath = router.routesById[this.id as string].fullPath
140140
return <Link from={fullPath as never} {...props} />
141-
}
141+
}) as LinkComponentRoute<RouteTypesById<TRouter, TId>['fullPath']>
142142
}
143143

144144
export class Route<
@@ -242,9 +242,9 @@ export class Route<
242242
return useNavigate({ from: this.fullPath })
243243
}
244244

245-
Link: LinkComponentRoute<TFullPath> = (props) => {
245+
Link: LinkComponentRoute<TFullPath> = ((props) => {
246246
return <Link from={this.fullPath} {...props} />
247-
}
247+
}) as LinkComponentRoute<TFullPath>
248248
}
249249

250250
export function createRoute<
@@ -427,9 +427,9 @@ export class RootRoute<
427427
return useNavigate({ from: this.fullPath })
428428
}
429429

430-
Link: LinkComponentRoute<'/'> = (props) => {
430+
Link: LinkComponentRoute<'/'> = ((props) => {
431431
return <Link from={this.fullPath} {...(props as any)} />
432-
}
432+
}) as LinkComponentRoute<'/'>
433433
}
434434

435435
export function createRouteMask<

0 commit comments

Comments
 (0)