Skip to content

Commit f6be2df

Browse files
authored
perf: improve ts perf for Route.Link (#4104)
1 parent 144a33c commit f6be2df

File tree

6 files changed

+49
-19
lines changed

6 files changed

+49
-19
lines changed

packages/react-router/src/link.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,21 @@ 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
482+
468483
export function createLink<const TComp>(
469484
Comp: Constrain<TComp, any, (props: CreateLinkProps) => ReactNode>,
470485
): LinkComponent<TComp> {

packages/react-router/src/route.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import type { UseLoaderDepsRoute } from './useLoaderDeps'
4242
import type { UseParamsRoute } from './useParams'
4343
import type { UseSearchRoute } from './useSearch'
4444
import type { UseRouteContextRoute } from './useRouteContext'
45-
import type { LinkComponent } from './link'
45+
import type { LinkComponentRoute } from './link'
4646

4747
declare module '@tanstack/router-core' {
4848
export interface UpdatableRouteOptionsExtensions {
@@ -63,7 +63,7 @@ declare module '@tanstack/router-core' {
6363
useLoaderDeps: UseLoaderDepsRoute<TId>
6464
useLoaderData: UseLoaderDataRoute<TId>
6565
useNavigate: () => UseNavigateResult<TFullPath>
66-
Link: LinkComponent<'a', TFullPath>
66+
Link: LinkComponentRoute<TFullPath>
6767
}
6868
}
6969

@@ -137,13 +137,12 @@ export class RouteApi<
137137
return notFound({ routeId: this.id as string, ...opts })
138138
}
139139

140-
Link: LinkComponent<'a', RouteTypesById<TRouter, TId>['fullPath']> =
140+
Link: LinkComponentRoute<RouteTypesById<TRouter, TId>['fullPath']> =
141141
React.forwardRef((props, ref: React.ForwardedRef<HTMLAnchorElement>) => {
142142
const router = useRouter()
143143
const fullPath = router.routesById[this.id as string].fullPath
144144
return <Link ref={ref} from={fullPath as never} {...props} />
145-
}) as unknown as LinkComponent<
146-
'a',
145+
}) as unknown as LinkComponentRoute<
147146
RouteTypesById<TRouter, TId>['fullPath']
148147
>
149148
}
@@ -255,11 +254,11 @@ export class Route<
255254
return useNavigate({ from: this.fullPath })
256255
}
257256

258-
Link: LinkComponent<'a', TFullPath> = React.forwardRef(
257+
Link: LinkComponentRoute<TFullPath> = React.forwardRef(
259258
(props, ref: React.ForwardedRef<HTMLAnchorElement>) => {
260259
return <Link ref={ref} from={this.fullPath as never} {...props} />
261260
},
262-
) as unknown as LinkComponent<'a', TFullPath>
261+
) as unknown as LinkComponentRoute<TFullPath>
263262
}
264263

265264
export function createRoute<
@@ -446,11 +445,11 @@ export class RootRoute<
446445
return useNavigate({ from: this.fullPath })
447446
}
448447

449-
Link: LinkComponent<'a', '/'> = React.forwardRef(
448+
Link: LinkComponentRoute<'/'> = React.forwardRef(
450449
(props, ref: React.ForwardedRef<HTMLAnchorElement>) => {
451450
return <Link ref={ref} from={this.fullPath} {...props} />
452451
},
453-
) as unknown as LinkComponent<'a', '/'>
452+
) as unknown as LinkComponentRoute<'/'>
454453
}
455454

456455
export function createRootRoute<

packages/react-router/tests/routeApi.test-d.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { describe, expectTypeOf, test } from 'vitest'
22
import { createRootRoute, createRoute, createRouter, getRouteApi } from '../src'
3-
import type { LinkComponent, MakeRouteMatch, UseNavigateResult } from '../src'
3+
import type { MakeRouteMatch, UseNavigateResult } from '../src'
4+
import type { LinkComponentRoute } from '../src/link'
45

56
const rootRoute = createRootRoute()
67

@@ -90,7 +91,7 @@ describe('getRouteApi', () => {
9091
test('Link', () => {
9192
const Link = invoiceRouteApi.Link
9293
expectTypeOf(Link).toEqualTypeOf<
93-
LinkComponent<'a', '/invoices/$invoiceId'>
94+
LinkComponentRoute<'/invoices/$invoiceId'>
9495
>()
9596
})
9697
})

packages/solid-router/src/link.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,21 @@ 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
539+
525540
export function createLink<const TComp>(
526541
Comp: Constrain<TComp, any, (props: CreateLinkProps) => Solid.JSX.Element>,
527542
): LinkComponent<TComp> {

packages/solid-router/src/route.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import type { UseParamsRoute } from './useParams'
4242
import type { UseSearchRoute } from './useSearch'
4343
import type * as Solid from 'solid-js'
4444
import type { UseRouteContextRoute } from './useRouteContext'
45-
import type { LinkComponent } from './link'
45+
import type { LinkComponentRoute } from './link'
4646

4747
declare module '@tanstack/router-core' {
4848
export interface UpdatableRouteOptionsExtensions {
@@ -63,7 +63,7 @@ declare module '@tanstack/router-core' {
6363
useLoaderDeps: UseLoaderDepsRoute<TId>
6464
useLoaderData: UseLoaderDataRoute<TId>
6565
useNavigate: () => UseNavigateResult<TFullPath>
66-
Link: LinkComponent<'a', TFullPath>
66+
Link: LinkComponentRoute<TFullPath>
6767
}
6868
}
6969

@@ -132,7 +132,7 @@ export class RouteApi<
132132
return notFound({ routeId: this.id as string, ...opts })
133133
}
134134

135-
Link: LinkComponent<'a', RouteTypesById<TRouter, TId>['fullPath']> = (
135+
Link: LinkComponentRoute<RouteTypesById<TRouter, TId>['fullPath']> = (
136136
props,
137137
) => {
138138
const router = useRouter()
@@ -242,7 +242,7 @@ export class Route<
242242
return useNavigate({ from: this.fullPath })
243243
}
244244

245-
Link: LinkComponent<'a', TFullPath> = (props) => {
245+
Link: LinkComponentRoute<TFullPath> = (props) => {
246246
return <Link from={this.fullPath} {...props} />
247247
}
248248
}
@@ -427,8 +427,8 @@ export class RootRoute<
427427
return useNavigate({ from: this.fullPath })
428428
}
429429

430-
Link: LinkComponent<'a', '/'> = (props) => {
431-
return <Link from={this.fullPath} {...props} />
430+
Link: LinkComponentRoute<'/'> = (props) => {
431+
return <Link from={this.fullPath} {...(props as any)} />
432432
}
433433
}
434434

packages/solid-router/tests/routeApi.test-d.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { describe, expectTypeOf, test } from 'vitest'
22
import { createRootRoute, createRoute, createRouter, getRouteApi } from '../src'
3-
import type { LinkComponent } from '../src'
43
import type { Accessor } from 'solid-js'
54
import type { MakeRouteMatch, UseNavigateResult } from '@tanstack/router-core'
5+
import type { LinkComponentRoute } from '../src/link'
66

77
const rootRoute = createRootRoute()
88

@@ -100,7 +100,7 @@ describe('getRouteApi', () => {
100100
test('Link', () => {
101101
const Link = invoiceRouteApi.Link
102102
expectTypeOf(Link).toEqualTypeOf<
103-
LinkComponent<'a', '/invoices/$invoiceId'>
103+
LinkComponentRoute<'/invoices/$invoiceId'>
104104
>()
105105
})
106106
})

0 commit comments

Comments
 (0)