Framework
Version
Integrationen

Typ-Dienstprogramme

Die meisten von TanStack Router bereitgestellten Typen sind intern, unterliegen Breaking Changes und sind nicht immer einfach zu verwenden. Aus diesem Grund verfügt TanStack Router über eine Teilmenge von bereitgestellten Typen, die auf Benutzerfreundlichkeit ausgelegt sind und extern verwendet werden können. Diese Typen bieten dieselbe typsichere Erfahrung aus den Laufzeitkonzepten von TanStack Router auf der Typpentypenebene, mit der Flexibilität, wo die Typüberprüfung bereitgestellt werden kann.

ValidateLinkOptions überprüft Literal-Objekttypen, um sicherzustellen, dass sie an den Inferenzstellen den Link-Optionen entsprechen. Sie können beispielsweise eine generische HeadingLink-Komponente haben, die eine title-Prop zusammen mit linkOptions akzeptiert. Die Idee dahinter ist, dass diese Komponente für jede Navigation wiederverwendet werden kann.

tsx
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>,
): React.ReactNode
export function HeadingLink(props: HeaderLinkProps): React.ReactNode {
  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>,
): React.ReactNode
export function HeadingLink(props: HeaderLinkProps): React.ReactNode {
  return (
    <>
      <h1>{props.title}</h1>
      <Link {...props.linkOptions} />
    </>
  )
}

Eine permissivere Überladung von HeadingLink wird verwendet, um Typassertionen zu vermeiden, die Sie sonst mit der generischen Signatur durchführen müssten. Die Verwendung einer lockeren Signatur ohne Typparameter ist eine einfache Möglichkeit, Typassertionen in der Implementierung von HeadingLink zu vermeiden.

Alle Typparameter für Utilities sind optional, aber für die beste TypeScript-Performance sollte TRouter immer für die öffentlich zugängliche Signatur angegeben werden. Und TOptions sollte immer an Inferenzstellen wie HeadingLink verwendet werden, um die linkOptions zu inferieren und params und search korrekt einzugrenzen.

Das Ergebnis ist, dass linkOptions in der folgenden Darstellung vollständig typsicher sind.

tsx
<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-Utilities haben eine Array-Variante. ValidateLinkOptionsArray ermöglicht die Typüberprüfung eines Arrays von Link-Optionen. Sie könnten beispielsweise eine generische Menu-Komponente haben, bei der jedes Element ein Link ist.

tsx
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>): React.ReactNode
export function Menu(props: MenuProps): React.ReactNode {
  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>): React.ReactNode
export function Menu(props: MenuProps): React.ReactNode {
  return (
    <ul>
      {props.items.map((item) => (
        <li>
          <Link {...item} />
        </li>
      ))}
    </ul>
  )
}

Dies ermöglicht es natürlich, dass die folgende items-Prop vollständig typsicher ist.

tsx
<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 festzulegen. Dies würde es allen Menu-Elementen ermöglichen, relativ zu from zu navigieren. Zusätzliche Typüberprüfung von from kann durch das Utility ValidateFromPath bereitgestellt werden.

tsx
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>): React.ReactNode
export function Menu(props: MenuProps): React.ReactNode {
  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>): React.ReactNode
export function Menu(props: MenuProps): React.ReactNode {
  return (
    <ul>
      {props.items.map((item) => (
        <li>
          <Link {...item} from={props.from} />
        </li>
      ))}
    </ul>
  )
}

ValidateLinkOptionsArray ermöglicht es Ihnen, from durch Angabe eines zusätzlichen Typparameters festzulegen. Das Ergebnis ist ein typsicheres Array von Link-Optionen, die Navigation relativ zu from bereitstellen.

tsx
<Menu
  from="/posts"
  items={[{ to: '.' }, { to: './$postId', params: { postId: 'postId' } }]}
/>
<Menu
  from="/posts"
  items={[{ to: '.' }, { to: './$postId', params: { postId: 'postId' } }]}
/>

Typüberprüfung von Redirect-Optionen mit ValidateRedirectOptions

ValidateRedirectOptions überprüft Literal-Objekttypen, um sicherzustellen, dass sie an den Inferenzstellen den Redirect-Optionen entsprechen. Sie benötigen möglicherweise beispielsweise eine generische Funktion fetchOrRedirect, die eine url zusammen mit redirectOptions akzeptiert. Die Idee ist, dass diese Funktion umleitet, wenn der fetch fehlschlägt.

tsx
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.

tsx
fetchOrRedirect('http://example.com/', { to: '/login' })
fetchOrRedirect('http://example.com/', { to: '/login' })

Typüberprüfung von Navigate-Optionen mit ValidateNavigateOptions

ValidateNavigateOptions überprüft Literal-Objekttypen, um sicherzustellen, dass sie an den Inferenzstellen den Navigate-Optionen entsprechen. Sie möchten beispielsweise einen benutzerdefinierten Hook schreiben, um die Navigation zu aktivieren/deaktivieren.

tsx
export interface UseConditionalNavigateResult {
  enable: () => void
  disable: () => void
  navigate: () => void
}

export function useConditionalNavigate<
  TRouter extends RegisteredRouter = RegisteredRouter,
  TOptions,
>(
  navigateOptions: ValidateNavigateOptions<TRouter, TOptions>,
): UseConditionalNavigateResult
export function useConditionalNavigate(
  navigateOptions: ValidateNavigateOptions,
): UseConditionalNavigateResult {
  const [enabled, setEnabled] = useState(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 = RegisteredRouter,
  TOptions,
>(
  navigateOptions: ValidateNavigateOptions<TRouter, TOptions>,
): UseConditionalNavigateResult
export function useConditionalNavigate(
  navigateOptions: ValidateNavigateOptions,
): UseConditionalNavigateResult {
  const [enabled, setEnabled] = useState(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.

tsx
const { enable, disable, navigate } = useConditionalNavigate({
  to: '/posts/$postId',
  params: { postId: 'postId' },
})
const { enable, disable, navigate } = useConditionalNavigate({
  to: '/posts/$postId',
  params: { postId: 'postId' },
})
Unsere Partner
Code Rabbit
Netlify
Neon
Clerk
Convex
Sentry
Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.

Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.