Die meisten von TanStack Router bereitgestellten Typen sind intern, unterliegen Änderungen und sind nicht immer einfach zu verwenden. Deshalb hat TanStack Router eine Teilmenge von bereitgestellten Typen, die auf einfache Verwendung ausgerichtet sind und extern verwendet werden sollen. Diese Typen bieten die gleiche typsichere Erfahrung von TanStack Routers Laufzeitkonzepten auf der Typenebene, mit der Flexibilität, wo die Typüberprüfung bereitgestellt werden soll.
ValidateLinkOptions überprüft Objektliteraltypen, um sicherzustellen, dass sie mit den Link-Optionen an Inferenzstellen konform sind. Sie können beispielsweise eine generische HeadingLink-Komponente haben, die eine title-Prop zusammen mit linkOptions akzeptiert. Die Idee ist, dass diese Komponente für jede Navigation wiederverwendet werden kann.
export interface HeaderLinkProps<
TRouter extends RegisteredRouter = RegisteredRouter,
TOptions = unknown,
> {
title: string
linkOptions: ValidateLinkOptions<TRouter, TOptions>
}
export function HeadingLink<TRouter extends RegisteredRouter, TOptions>(
props: HeaderLinkProps<TRouter, TOptions>,
): Solid.JSX.Element
export function HeadingLink(props: HeaderLinkProps): Solid.JSX.Element {
return (
<>
<h1>{props.title}</h1>
<Link {...props.linkOptions} />
</>
)
}
export interface HeaderLinkProps<
TRouter extends RegisteredRouter = RegisteredRouter,
TOptions = unknown,
> {
title: string
linkOptions: ValidateLinkOptions<TRouter, TOptions>
}
export function HeadingLink<TRouter extends RegisteredRouter, TOptions>(
props: HeaderLinkProps<TRouter, TOptions>,
): Solid.JSX.Element
export function HeadingLink(props: HeaderLinkProps): Solid.JSX.Element {
return (
<>
<h1>{props.title}</h1>
<Link {...props.linkOptions} />
</>
)
}
Eine permissivere Überladung von HeadingLink wird verwendet, um Typzusicherungen zu vermeiden, die Sie sonst mit der generischen Signatur machen müssten. Die Verwendung einer lockereren Signatur ohne Typparameter ist eine einfache Möglichkeit, Typzusicherungen in der Implementierung von HeadingLink zu vermeiden.
Alle Typparameter für Dienstprogramme sind optional, aber für die beste TypeScript-Leistung sollte TRouter immer für die öffentliche Signatur angegeben werden. Und TOptions sollte immer an Inferenzstellen wie HeadingLink verwendet werden, um linkOptions abzuleiten und params und search korrekt einzuschränken.
Das Ergebnis ist, dass linkOptions im Folgenden vollständig typsicher ist.
<HeadingLink title="Posts" linkOptions={{ to: '/posts' }} />
<HeadingLink title="Post" linkOptions={{ to: '/posts/$postId', params: {postId: 'postId'} }} />
<HeadingLink title="Posts" linkOptions={{ to: '/posts' }} />
<HeadingLink title="Post" linkOptions={{ to: '/posts/$postId', params: {postId: 'postId'} }} />
Alle Navigations-Typ-Dienstprogramme haben eine Array-Variante. ValidateLinkOptionsArray ermöglicht die Typüberprüfung eines Arrays von Link-Optionen. Sie könnten zum Beispiel eine generische Menu-Komponente haben, bei der jedes Element ein Link ist.
export interface MenuProps<
TRouter extends RegisteredRouter = RegisteredRouter,
TItems extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,
> {
items: ValidateLinkOptionsArray<TRouter, TItems>
}
export function Menu<
TRouter extends RegisteredRouter = RegisteredRouter,
TItems extends ReadonlyArray<unknown>,
>(props: MenuProps<TRouter, TItems>): Solid.JSX.Element
export function Menu(props: MenuProps): Solid.JSX.Element {
return (
<ul>
{props.items.map((item) => (
<li>
<Link {...item} />
</li>
))}
</ul>
)
}
export interface MenuProps<
TRouter extends RegisteredRouter = RegisteredRouter,
TItems extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,
> {
items: ValidateLinkOptionsArray<TRouter, TItems>
}
export function Menu<
TRouter extends RegisteredRouter = RegisteredRouter,
TItems extends ReadonlyArray<unknown>,
>(props: MenuProps<TRouter, TItems>): Solid.JSX.Element
export function Menu(props: MenuProps): Solid.JSX.Element {
return (
<ul>
{props.items.map((item) => (
<li>
<Link {...item} />
</li>
))}
</ul>
)
}
Dies ermöglicht natürlich, dass die folgende items-Prop vollständig typsicher ist.
<Menu
items={[
{ to: '/posts' },
{ to: '/posts/$postId', params: { postId: 'postId' } },
]}
/>
<Menu
items={[
{ to: '/posts' },
{ to: '/posts/$postId', params: { postId: 'postId' } },
]}
/>
Es ist auch möglich, from für jede Link-Option im Array zu fixieren. Dies würde es allen Menu-Elementen ermöglichen, relativ zu from zu navigieren. Zusätzliche Typüberprüfung von from kann durch das Dienstprogramm ValidateFromPath bereitgestellt werden.
export interface MenuProps<
TRouter extends RegisteredRouter = RegisteredRouter,
TItems extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,
TFrom extends string = string,
> {
from: ValidateFromPath<TRouter, TFrom>
items: ValidateLinkOptionsArray<TRouter, TItems, TFrom>
}
export function Menu<
TRouter extends RegisteredRouter = RegisteredRouter,
TItems extends ReadonlyArray<unknown>,
TFrom extends string = string,
>(props: MenuProps<TRouter, TItems, TFrom>): Solid.JSX.Element
export function Menu(props: MenuProps): Solid.JSX.Element {
return (
<ul>
{props.items.map((item) => (
<li>
<Link {...item} from={props.from} />
</li>
))}
</ul>
)
}
export interface MenuProps<
TRouter extends RegisteredRouter = RegisteredRouter,
TItems extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,
TFrom extends string = string,
> {
from: ValidateFromPath<TRouter, TFrom>
items: ValidateLinkOptionsArray<TRouter, TItems, TFrom>
}
export function Menu<
TRouter extends RegisteredRouter = RegisteredRouter,
TItems extends ReadonlyArray<unknown>,
TFrom extends string = string,
>(props: MenuProps<TRouter, TItems, TFrom>): Solid.JSX.Element
export function Menu(props: MenuProps): Solid.JSX.Element {
return (
<ul>
{props.items.map((item) => (
<li>
<Link {...item} from={props.from} />
</li>
))}
</ul>
)
}
ValidateLinkOptionsArray ermöglicht es Ihnen, from durch Bereitstellung eines zusätzlichen Typparameters zu fixieren. Das Ergebnis ist ein typsicheres Array von Link-Optionen, die die Navigation relativ zu from bereitstellen.
<Menu
from="/posts"
items={[{ to: '.' }, { to: './$postId', params: { postId: 'postId' } }]}
/>
<Menu
from="/posts"
items={[{ to: '.' }, { to: './$postId', params: { postId: 'postId' } }]}
/>
ValidateRedirectOptions überprüft Objektliteraltypen, um sicherzustellen, dass sie mit Weiterleitungsoptionen an Inferenzstellen konform sind. Sie benötigen möglicherweise beispielsweise eine generische Funktion fetchOrRedirect, die eine url zusammen mit redirectOptions akzeptiert. Die Idee ist, dass diese Funktion weiterleitet, wenn der fetch fehlschlägt.
export async function fetchOrRedirect<
TRouter extends RegisteredRouter = RegisteredRouter,
TOptions,
>(
url: string,
redirectOptions: ValidateRedirectOptions<TRouter, TOptions>,
): Promise<unknown>
export async function fetchOrRedirect(
url: string,
redirectOptions: ValidateRedirectOptions,
): Promise<unknown> {
const response = await fetch(url)
if (!response.ok && response.status === 401) {
throw redirect(redirectOptions)
}
return await response.json()
}
export async function fetchOrRedirect<
TRouter extends RegisteredRouter = RegisteredRouter,
TOptions,
>(
url: string,
redirectOptions: ValidateRedirectOptions<TRouter, TOptions>,
): Promise<unknown>
export async function fetchOrRedirect(
url: string,
redirectOptions: ValidateRedirectOptions,
): Promise<unknown> {
const response = await fetch(url)
if (!response.ok && response.status === 401) {
throw redirect(redirectOptions)
}
return await response.json()
}
Das Ergebnis ist, dass redirectOptions, die an fetchOrRedirect übergeben werden, vollständig typsicher sind.
fetchOrRedirect('http://example.com/', { to: '/login' })
fetchOrRedirect('http://example.com/', { to: '/login' })
ValidateNavigateOptions überprüft Objektliteraltypen, um sicherzustellen, dass sie mit Navigationsoptionen an Inferenzstellen konform sind. Sie möchten beispielsweise einen benutzerdefinierten Hook schreiben, um die Navigation zu aktivieren/deaktivieren.
export interface UseConditionalNavigateResult {
enable: () => void
disable: () => void
navigate: () => void
}
export function useConditionalNavigate<
TRouter extends RegisteredRouter,
TOptions,
>(
navigateOptions: ValidateNavigateOptions<TRouter, TOptions>,
): UseConditionalNavigateResult
export function useConditionalNavigate(
navigateOptions: ValidateNavigateOptions,
): UseConditionalNavigateResult {
const [enabled, setEnabled] = createSignal(false)
const navigate = useNavigate()
return {
enable: () => setEnabled(true),
disable: () => setEnabled(false),
navigate: () => {
if (enabled) {
navigate(navigateOptions)
}
},
}
}
export interface UseConditionalNavigateResult {
enable: () => void
disable: () => void
navigate: () => void
}
export function useConditionalNavigate<
TRouter extends RegisteredRouter,
TOptions,
>(
navigateOptions: ValidateNavigateOptions<TRouter, TOptions>,
): UseConditionalNavigateResult
export function useConditionalNavigate(
navigateOptions: ValidateNavigateOptions,
): UseConditionalNavigateResult {
const [enabled, setEnabled] = createSignal(false)
const navigate = useNavigate()
return {
enable: () => setEnabled(true),
disable: () => setEnabled(false),
navigate: () => {
if (enabled) {
navigate(navigateOptions)
}
},
}
}
Das Ergebnis ist, dass navigateOptions, die an useConditionalNavigate übergeben werden, vollständig typsicher sind und wir die Navigation basierend auf dem React-Status aktivieren/deaktivieren können.
const { enable, disable, navigate } = useConditionalNavigate({
to: '/posts/$postId',
params: { postId: 'postId' },
})
const { enable, disable, navigate } = useConditionalNavigate({
to: '/posts/$postId',
params: { postId: 'postId' },
})
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.