Skip to content

Hook results take the caller's expected type when no select is passed (useLoaderData, useSearch, ...) #8666

Open

Description

@czarandy

Which project does this relate to?

Router

Describe the bug

Without select, the hooks' TSelected is inferred from the call site's expected type, so the hook "returns" whatever the caller wants and wrong usage typechecks:

const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/posts',
  loader: () => ({ posts: ['first post'] }),
})

const data = postsRoute.useLoaderData()
const a: number = data                       // error, as expected
const b: number = postsRoute.useLoaderData() // no error
takesNumber(postsRoute.useLoaderData())      // no error

The result types are unknown extends TSelected ? Resolved : TSelected. TypeScript infers type arguments from the contextual return type too, and with no select that is the only inference site, so TSelected becomes number.

Affected: useLoaderData, useSearch, useParams, useRouteContext, useLoaderDeps, useMatch, useLocation, useRouterState, useMatches / useParentMatches / useChildMatches (the route-bound and getRouteApi forms too), in react, solid and vue.

We hit this when passing Route.useLoaderData() straight into a prop of a different type; it typechecked and only misbehaved at runtime.

Complete minimal reproducer

https://github.com/czarandy/tanstack-router-select-inference-repro

Steps to Reproduce the Bug

  1. npm install && npm run typecheck
  2. It passes. Every line marked "Bug" in src/repro.ts should be an error.

Expected behavior

With no select, the result is the route's real type regardless of where the call sits, so const b: number = postsRoute.useLoaderData() is an error.

Fix: NoInfer<TSelected> in the false branch of each result type, so TSelected is inferred only from select. PR: #8667

Screenshots or Videos

No response

Platform

  • Router / Start Version: @tanstack/react-router 1.170.42
  • OS: Linux
  • Browser: n/a (type-level)
  • Browser Version: n/a
  • Bundler: n/a (tsc)
  • Bundler Version: TypeScript 5.9.3

Additional context

Written with AI assistance (Claude Code).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions