Capítulo 47 de 57

Chapter 47: Type Safety

Core Idea

TanStack Router fully infers and pipes types through the entire routing experience; achieving this for shared hooks/components requires a from context hint (or strict: false) since component context can't otherwise track changing route types.

Key Concepts

  • Router registration: Declaration merging on the Register interface (declare module '@tanstack/react-router' { interface Register { router: typeof router } }) is what makes top-level exports like Link, useNavigate, useParams type-safe project-wide.
  • getParentRoute: In code-based routing, child routes must reference their parent via getParentRoute so parent context/search/params types propagate down; omitting this loses type information.
  • The from hint: Hooks/components that need context from the whole router (e.g. useNavigate, Route.useParams) accept a from option (route ID or path) telling TypeScript where in the hierarchy the component renders.
  • Wrong from runtime error: Passing a from that satisfies TypeScript but doesn't match the actual rendering route throws a runtime error, it's checked, not just decorative.
  • strict: false: For shared components that don't know their route, this option relaxes the hook (e.g. useSearch({ strict: false })) to accept a union of all possible types instead of erroring.
  • createRootRouteWithContext: Factory for typing router context, requiring you to fulfill the same context contract when creating the router.
  • TS performance narrowing: Passing from/to narrows unions (search/params) TypeScript has to check; using broad types like LinkProps directly is expensive, prefer as const satisfies LinkProps<...>.

Code Examples

export const Route = createFileRoute('/posts')({
  component: PostsComponent,
})

function PostsComponent() {
  const params = Route.useParams()
  const search = Route.useSearch()
  const navigate = useNavigate({ from: Route.fullPath })
}
  • What it demonstrates: Using route-scoped hooks (Route.useParams) versus router-wide hooks that need an explicit from hint.
function MyComponent() {
  const search = useSearch({ strict: false })
}
  • What it demonstrates: Relaxed typing for shared components that can't declare a specific from.

Key Takeaways

  1. Register your router type once; it's the foundation that makes every other type-safe API in the library work.
  2. Always pass from (or Route.fullPath) to router-wide hooks used inside a specific route to get precise, narrowed types and catch runtime mismatches.
  3. For truly generic/shared components, use strict: false rather than guessing a from.
  4. For TS performance at scale: narrow with from/to, prefer as const satisfies LinkProps<...> over the bare LinkProps type, and consider object-syntax addChildren for large code-based route trees.

Connects To

  • Ch 44: Creating a Router, covers the initial router registration step this chapter builds on.
  • Ch 49: Router Context, createRootRouteWithContext and context typing are detailed there.
  • Ch 48: Type Utilities, provides ValidateLinkOptions and friends for building type-safe wrapper components without the LinkProps performance trap.