H
Hono4w ago
Manqo

Help setting up Hono RPC types between backend and Expo client

Hey, I’m using Hono for my backend and React Native (Expo) for my client, and I’m trying to set up Hono RPC with type safety shared between the two. Here’s my project structure:
project/
├── client/
│ └── src/
└── server/
└── src/
project/
├── client/
│ └── src/
└── server/
└── src/
Server (index.ts):
import { serve } from "@hono/node-server"
import { Hono } from "hono"
import { cors } from "hono/cors"
import storiesRouter from "@/routes/stories"
import { sessionMiddleware, type AppEnv } from "@/middlewares/auth"

const app = new Hono<AppEnv>()
app.use("*", cors())
app.use("*", sessionMiddleware)
app.route("/stories", storiesRouter)
app.get("/", (c) => c.text("Hello Hono!"))
serve({ fetch: app.fetch, port: 3001 })

export type AppType = typeof app
import { serve } from "@hono/node-server"
import { Hono } from "hono"
import { cors } from "hono/cors"
import storiesRouter from "@/routes/stories"
import { sessionMiddleware, type AppEnv } from "@/middlewares/auth"

const app = new Hono<AppEnv>()
app.use("*", cors())
app.use("*", sessionMiddleware)
app.route("/stories", storiesRouter)
app.get("/", (c) => c.text("Hello Hono!"))
serve({ fetch: app.fetch, port: 3001 })

export type AppType = typeof app
Client (honoClient.ts):
import { Platform } from "react-native"
import { hc } from "hono/client"
import { API_BASE_URL } from "./config"
import type { AppType } from "../../../server/src/index"

export const honoClient = hc<AppType>(API_BASE_URL, {
init: { credentials: Platform.OS === "web" ? "include" : "omit" },
})
import { Platform } from "react-native"
import { hc } from "hono/client"
import { API_BASE_URL } from "./config"
import type { AppType } from "../../../server/src/index"

export const honoClient = hc<AppType>(API_BASE_URL, {
init: { credentials: Platform.OS === "web" ? "include" : "omit" },
})
But when I import AppType, I get:
Type instantiation is excessively deep and possibly infinite.
(alias) type AppType = Hono<AppEnv, BlankSchema, "/">
Type instantiation is excessively deep and possibly infinite.
(alias) type AppType = Hono<AppEnv, BlankSchema, "/">
How should I define AppType so the client can use Hono RPC types correctly?
2 Replies
Manqo
ManqoOP4w ago
I fixed the infinite issue, but still don’t get types from the server.
// client/src/api/stories.ts
import { honoClient } from '@/src/api/honoClient'
import type { InferResponseType } from 'hono/client'

type StoriesList = InferResponseType<typeof honoClient.stories.$get, 200>

export async function fetchStories() {
const res = await honoClient.stories.$get()
if (!res.ok) throw new Error('Failed to fetch stories')
return res.json() as Promise<StoriesList>
}
// client/src/api/stories.ts
import { honoClient } from '@/src/api/honoClient'
import type { InferResponseType } from 'hono/client'

type StoriesList = InferResponseType<typeof honoClient.stories.$get, 200>

export async function fetchStories() {
const res = await honoClient.stories.$get()
if (!res.ok) throw new Error('Failed to fetch stories')
return res.json() as Promise<StoriesList>
}
The problem:
Property 'stories' does not exist on type 'unknown'.ts(2339)
honoClient setup:
// client/src/lib/honoClient.ts
import { hc } from 'hono/client'
import { API_BASE_URL } from './config'
import type { AppType } from '@server-app'

export const honoClient = hc<AppType>(API_BASE_URL, {
init: { credentials: 'include' },
})
// client/src/lib/honoClient.ts
import { hc } from 'hono/client'
import { API_BASE_URL } from './config'
import type { AppType } from '@server-app'

export const honoClient = hc<AppType>(API_BASE_URL, {
init: { credentials: 'include' },
})
AppType resolves to:
type AppType = Hono<AppEnv, BlankSchema, "/">
type AppType = Hono<AppEnv, BlankSchema, "/">
Server setup:
// server/index.ts
import { serve } from '@hono/node-server'
import { app } from './app'
serve({ fetch: app.fetch, port: 3001 })
export default app
// server/index.ts
import { serve } from '@hono/node-server'
import { app } from './app'
serve({ fetch: app.fetch, port: 3001 })
export default app
// server/app.ts
import { Hono } from 'hono'
import storiesRouter from '@/routes/stories'
export const app = new Hono<AppEnv>()
app.route('/stories', storiesRouter)
export type AppType = typeof app
// server/app.ts
import { Hono } from 'hono'
import storiesRouter from '@/routes/stories'
export const app = new Hono<AppEnv>()
app.route('/stories', storiesRouter)
export type AppType = typeof app
In short: honoClient.stories is typed as unknown, even though AppType is exported from the server. also client tsconfig:
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"moduleResolution": "Bundler", // <— match server to avoid resolver mismatch
"strict": false,
"paths": {
"@server-app": ["../server/dist/src/app"], // <-- notice /src/app
"@/*": [
"./*",
"../server/src/*"
]
}
},
"include": [
"**/*.ts",
"**/*.tsx",
".expo/types/**/*.ts",
"expo-env.d.ts"
]
}
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"moduleResolution": "Bundler", // <— match server to avoid resolver mismatch
"strict": false,
"paths": {
"@server-app": ["../server/dist/src/app"], // <-- notice /src/app
"@/*": [
"./*",
"../server/src/*"
]
}
},
"include": [
"**/*.ts",
"**/*.tsx",
".expo/types/**/*.ts",
"expo-env.d.ts"
]
}
` And server tsconfig:
// server/tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"skipLibCheck": true,
"verbatimModuleSyntax": true,
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"paths": { "@/*": ["./src/*"] },
"types": ["node"],
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
},
"exclude": ["dist","node_modules"]
}
// server/tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"skipLibCheck": true,
"verbatimModuleSyntax": true,
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"paths": { "@/*": ["./src/*"] },
"types": ["node"],
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
},
"exclude": ["dist","node_modules"]
}
`
ambergristle
ambergristle4w ago
https://discord.com/channels/1011308539819597844/1433317799039598704 hono types get big quick. you need to import generated types instead of directly importing the result of typeof app

Did you find this page helpful?