tRPC v11 で型エラー・動かない時の対処法:v10からの移行で詰まる5つの破壊的変更【React Query v5 / createCallerFactory】
公開日:2026-07-22/カテゴリ:tRPC・TypeScript・React・Next.js/AnchorUp 技術ブログ
まず確認:tRPC v11 で動かない時の症状と対策(結論)
tRPC v11 は v10 との間に複数の破壊的変更がある。アップグレード後に型エラーや実行時エラーが発生した場合は、まず以下の表で症状を照合すること。
| 症状 | 原因 | 対策 |
|---|---|---|
createTRPCReact が型エラー / import できない |
パッケージ構成が変わった | @trpc/react-query を v11 に合わせて更新 |
useQuery の型が合わない・ジェネリクスエラー |
React Query v5 が必須になった | @tanstack/react-query を v5 に上げる |
httpBatchLink から fetch 関連エラーが出る |
デフォルトリンクが httpBatchStreamLink になった |
httpBatchStreamLink に変更するか明示的に httpBatchLink を指定 |
サーバーサイドの createCaller が動かない |
createCallerFactory が新しい API になった |
appRouter.createCaller() から createCallerFactory に移行 |
superjson が Date を正しくシリアライズしない |
デフォルトトランスフォーマーが変わった | transformer: superjson を明示的に設定 |
tRPC v11 で何が変わったのか
tRPC v11 は「React Query v5 への対応」と「ストリーミングのデフォルト化」が主な変更軸だ。
主な破壊的変更:
- React Query v5 が必須(v4 は非対応)
httpBatchStreamLinkがデフォルトのリンクに- サーバーサイド呼び出しの API が
createCallerFactoryに刷新 - トランスフォーマー(superjson 等)の設定方法が変更
inferRouterInputs/inferRouterOutputsの型ユーティリティ名が変更
v10 で動いていたコードがそのままでは動かなくなるケースが多く、エラーメッセージから原因を特定しにくいことが多い。以降で症状ごとに詳細を解説する。
症状1: React Query v5 が入っていないと型エラーになる
エラーメッセージ
Type error: Type 'UseQueryResult<...>' is not assignable to type '...'
Module '"@tanstack/react-query"' has no exported member 'QueryOptions'
原因
tRPC v11 の @trpc/react-query は React Query v5 専用に設計されている。v4 では型が合わず、実行時エラーにもなる。
対処法
まず React Query を v5 にアップグレードする。
npm install @tanstack/react-query@5 @trpc/react-query@11 @trpc/client@11 @trpc/server@11
React Query v5 自体にも破壊的変更がある(useQuery のオプション名変更など)。tRPC の移行と同時に発生するため混乱しやすいが、分けて対処すること。
React Query v5 の主な変更点:
// v4 まで
const { data } = useQuery(['key'], fetcher, { onSuccess: (data) => {} })
// v5 から(コールバックが削除・options の形式が変更)
const { data } = useQuery({ queryKey: ['key'], queryFn: fetcher })
// onSuccess は useEffect で代替する
症状2: httpBatchStreamLink への移行
エラーメッセージ
Error: unable to transform response
RangeError: Invalid typed array length
原因
tRPC v11 では httpBatchStreamLink がデフォルト推奨リンクになった。v10 では httpBatchLink がデフォルトだったが、v11 では ストリーミングレスポンスを使う httpBatchStreamLink への移行が推奨されている。
サーバーサイドがストリーミングに対応していない場合(一部のエッジランタイムや Serverless 環境)、httpBatchStreamLink を使うとエラーになることがある。
対処法
ストリーミング対応環境(Node.js, Cloudflare Workers 等):
// trpc/client.ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client'
import type { AppRouter } from '../server/routers/_app'
export const trpc = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: '/api/trpc',
headers() {
return {
authorization: getAuthToken(),
}
},
}),
],
})
ストリーミング非対応環境(Vercel Serverless Functions の一部構成等):
// httpBatchLink を明示的に使う
import { createTRPCClient, httpBatchLink } from '@trpc/client'
export const trpc = createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: '/api/trpc',
}),
],
})
症状3: createCallerFactory でサーバーサイド呼び出しが動かない
エラーメッセージ
TypeError: appRouter.createCaller is not a function
Property 'createCaller' does not exist on type 'Router<...>'
原因
v10 では appRouter.createCaller(ctx) でサーバーサイド呼び出しができたが、v11 では createCallerFactory という新しい API に変わった。
対処法
v10 の書き方(非推奨):
// v10 まで
const caller = appRouter.createCaller({ user: session.user })
const result = await caller.user.getProfile()
v11 の書き方:
// server/trpc.ts
import { initTRPC } from '@trpc/server'
import type { Context } from './context'
const t = initTRPC.context<Context>().create()
export const router = t.router
export const publicProcedure = t.procedure
export const createCallerFactory = t.createCallerFactory // ← エクスポート
// server/routers/_app.ts
import { router } from '../trpc'
import { userRouter } from './user'
export const appRouter = router({
user: userRouter,
})
export type AppRouter = typeof appRouter
// Next.js の Server Component やサーバーサイド処理で使う
import { createCallerFactory } from '../server/trpc'
import { appRouter } from '../server/routers/_app'
import { createContext } from '../server/context'
// factory を作成(モジュールレベルで1回だけ)
const createCaller = createCallerFactory(appRouter)
// リクエストごとにコンテキストを渡してインスタンス化
const caller = createCaller(await createContext())
const profile = await caller.user.getProfile()
createCallerFactory を使うことで、コンテキストとルーターを分離して管理できるようになった。テストでモックコンテキストを差し込みやすくなるメリットもある。
症状4: superjson で Date が文字列になる・シリアライズが壊れる
症状
// サーバー側で Date を返しているのに、クライアントで string になる
const user = await trpc.user.getById.query(1)
console.log(user.createdAt) // "2024-01-01T00:00:00.000Z" (string)
console.log(user.createdAt instanceof Date) // false
原因
tRPC v11 ではデフォルトのデータシリアライザーが変更され、JSON のみになった。v10 まで superjson を明示的に設定していた場合、設定方法が変わっている。
対処法
npm install superjson
// server/trpc.ts
import { initTRPC } from '@trpc/server'
import superjson from 'superjson'
import type { Context } from './context'
const t = initTRPC.context<Context>().create({
transformer: superjson, // ← 明示的に指定する
})
export const router = t.router
export const publicProcedure = t.procedure
export const createCallerFactory = t.createCallerFactory
// trpc/client.ts(クライアント側にも同じトランスフォーマーを設定する)
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client'
import superjson from 'superjson'
import type { AppRouter } from '../server/routers/_app'
export const trpc = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: '/api/trpc',
transformer: superjson, // ← クライアント側にも設定
}),
],
})
サーバーとクライアントで 必ず同じトランスフォーマーを設定すること。片方だけ設定するとシリアライズ/デシリアライズのミスマッチが起きる。
症状5: inferRouterInputs / inferRouterOutputs の型が取れない
エラーメッセージ
Module '"@trpc/server"' has no exported member 'inferRouterInputs'
原因
v10 では @trpc/server から直接 inferRouterInputs / inferRouterOutputs をインポートできたが、v11 では型ユーティリティのインポートパスが整理された。
対処法
// v10 まで
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server'
// v11 から(同じパスで引き続き使える場合もあるが、ルーターから推論する方が安全)
import type { AppRouter } from './server/routers/_app'
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server'
type RouterInputs = inferRouterInputs<AppRouter>
type RouterOutputs = inferRouterOutputs<AppRouter>
// 使用例
type UserProfileInput = RouterInputs['user']['getProfile']
type UserProfileOutput = RouterOutputs['user']['getProfile']
インポートエラーが出る場合は tRPC 全パッケージのバージョンが揃っているか確認すること。
# バージョン確認
npm list @trpc/server @trpc/client @trpc/react-query @trpc/next
混在するとピア依存関係の不整合で型エラーが起きる。
Next.js App Router との組み合わせ
Next.js App Router で tRPC v11 を使う場合、createTRPCProxyClient ではなく createTRPCClient を使う(v11 では proxy 版は廃止)。
// app/trpc/server.ts(Server Components 用)
import { createCallerFactory } from '../../server/trpc'
import { appRouter } from '../../server/routers/_app'
import { createContext } from '../../server/context'
import { cache } from 'react'
// React の cache() でリクエストごとにメモ化
export const createCaller = cache(async () => {
const context = await createContext()
const factory = createCallerFactory(appRouter)
return factory(context)
})
// app/page.tsx(Server Component)
import { createCaller } from './trpc/server'
export default async function Page() {
const caller = await createCaller()
const users = await caller.user.list() // 型安全なサーバーサイド呼び出し
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
}
v10 から v11 への移行チェックリスト
□ @trpc/server, @trpc/client, @trpc/react-query をすべて v11 に更新した
□ @tanstack/react-query を v5 に更新した
□ appRouter.createCaller() を createCallerFactory に移行した
□ httpBatchLink を httpBatchStreamLink に変更(または環境に合わせて明示指定)した
□ superjson を使う場合、サーバーとクライアント両方に transformer を設定した
□ React Query v5 の破壊的変更(onSuccess 廃止等)にも対応した
まとめ
tRPC v11 で動かなくなる主な原因は React Query v5 への強制移行 と 新しいサーバーサイド呼び出し API(createCallerFactory)、そして デフォルトリンクの変更(httpBatchStreamLink) の3点だ。
createCaller→createCallerFactoryの移行が最もハマりやすい- React Query v5 も同時に破壊的変更があるため、両方の変更に対応する必要がある
superjsonは明示的にサーバー・クライアント両方に設定しないと Date が文字列になるhttpBatchStreamLinkはストリーミング対応環境でのみ有効。Vercel の一部設定等ではhttpBatchLinkを使う
パッケージのバージョンが混在しているとエラー原因の特定が難しくなるため、npm list @trpc/* でバージョンを揃えてから対処することを強くすすめる。