> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/honojs/hono/llms.txt
> Use this file to discover all available pages before exploring further.

# Type Safety

> End-to-end type inference from server to client with TypeScript

## End-to-End Type Safety

One of Hono's most powerful features is its end-to-end type safety. The RPC client uses TypeScript's type inference to automatically derive types from your server routes - no code generation or manual type definitions needed.

```typescript theme={null}
// Server
const app = new Hono()
  .get('/user', (c) => c.json({ id: 123, name: 'Alice' }))

// Client - types are automatically inferred
const client = hc<typeof app>('http://localhost')
const res = await client.user.$get()
const data = await res.json()

// TypeScript knows:
// data.id is number
// data.name is string
// data.email causes a type error (doesn't exist)
```

## Type Inference

TypeScript automatically infers types from your Hono app definition. This includes:

* Route paths and parameters
* Request body types (JSON, form data)
* Query parameters
* Response body types
* HTTP status codes

<Note>
  The type inference works entirely at compile time - there's no runtime overhead.
</Note>

## InferResponseType

The `InferResponseType` utility type extracts the response type from a client method:

```typescript theme={null}
import { hc } from 'hono/client'
import type { InferResponseType } from 'hono/client'

const app = new Hono()
  .get('/posts/:id', (c) => {
    return c.json({
      id: 123,
      title: 'Hello Hono',
      published: true
    })
  })

const client = hc<typeof app>('http://localhost')

// Extract the response type
type Post = InferResponseType<typeof client.posts[':id'].$get>
// Post = { id: number, title: string, published: boolean }
```

### Usage in Components

This is especially useful when passing data to components:

```typescript theme={null}
import type { InferResponseType } from 'hono/client'

type PostData = InferResponseType<typeof client.posts[':id'].$get>

function PostComponent({ post }: { post: PostData }) {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>ID: {post.id}</p>
    </div>
  )
}
```

## InferRequestType

The `InferRequestType` utility type extracts the request parameter types:

```typescript theme={null}
import type { InferRequestType } from 'hono/client'

const app = new Hono()
  .post('/posts', 
    validator('json', () => ({ title: '', content: '' })),
    (c) => c.json({ id: 123 }, 201)
  )

const client = hc<typeof app>('http://localhost')

// Extract request type
type CreatePostInput = InferRequestType<typeof client.posts.$post>
// CreatePostInput = { json: { title: string, content: string } }

// Use in functions
function createPost(data: CreatePostInput['json']) {
  return client.posts.$post({ json: data })
}
```

## Status Code Types

When your server returns different types based on status codes, the client preserves this information:

```typescript theme={null}
const app = new Hono()
  .get('/api/data', (c) => {
    const success = Math.random() > 0.5
    if (success) {
      return c.json({ data: 'Success!' }, 200)
    }
    return c.json({ error: 'Failed' }, 400)
  })

const client = hc<typeof app>('http://localhost')
const res = await client.api.data.$get()

// TypeScript knows the response type is a union
if (res.status === 200) {
  const data = await res.json()
  // data is { data: string }
  console.log(data.data)
} else if (res.status === 400) {
  const error = await res.json()
  // error is { error: string }
  console.log(error.error)
}
```

### InferResponseType with Status Codes

You can specify a status code to narrow the response type:

```typescript theme={null}
// Get only the 200 response type
type SuccessData = InferResponseType<typeof client.api.data.$get, 200>
// SuccessData = { data: string }

// Get only the 400 response type
type ErrorData = InferResponseType<typeof client.api.data.$get, 400>
// ErrorData = { error: string }
```

## Validation Types

When using validators on the server, the client automatically knows about required parameters:

```typescript theme={null}
import { validator } from 'hono/validator'

const app = new Hono()
  .get('/search',
    validator('query', () => ({ q: '', limit: 10 })),
    validator('header', () => ({ 'x-api-key': '' })),
    (c) => c.json({ results: [] })
  )

const client = hc<typeof app>('http://localhost')

// TypeScript enforces the query and header types
const res = await client.search.$get({
  query: { 
    q: 'hono',
    limit: 20  // TypeScript knows this should be a number
  },
  header: {
    'x-api-key': 'secret'
  }
})
```

## Request Body Types

### JSON Bodies

```typescript theme={null}
const app = new Hono()
  .post('/users',
    validator('json', () => ({
      name: '',
      email: '',
      age: 0
    })),
    (c) => c.json({ id: 1 }, 201)
  )

const client = hc<typeof app>('http://localhost')

// TypeScript enforces the JSON structure
await client.users.$post({
  json: {
    name: 'Alice',
    email: 'alice@example.com',
    age: 30
  }
})
```

### Form Data

```typescript theme={null}
const app = new Hono()
  .post('/upload',
    validator('form', () => ({ file: new File([], ''), title: '' })),
    (c) => c.json({ success: true })
  )

const client = hc<typeof app>('http://localhost')

// TypeScript knows the form structure
await client.upload.$post({
  form: {
    file: selectedFile,
    title: 'My Upload'
  }
})
```

## Optional and Required Parameters

The client automatically distinguishes between required and optional parameters:

```typescript theme={null}
const app = new Hono()
  // No input required
  .get('/status', (c) => c.json({ ok: true }))
  // Input required
  .post('/posts',
    validator('json', () => ({ title: '' })),
    (c) => c.json({ id: 1 })
  )

const client = hc<typeof app>('http://localhost')

// No arguments needed
await client.status.$get()

// Argument required (TypeScript error if omitted)
await client.posts.$post({
  json: { title: 'Hello' }
})
```

## Type-safe Response Methods

The client response object has typed methods based on the content type:

```typescript theme={null}
const app = new Hono()
  .get('/json', (c) => c.json({ data: 'value' }))
  .get('/text', (c) => c.text('Hello'))
  .get('/html', (c) => c.html('<h1>Hello</h1>'))

const client = hc<typeof app>('http://localhost')

// JSON responses
const jsonRes = await client.json.$get()
const data = await jsonRes.json() // { data: string }

// Text responses  
const textRes = await client.text.$get()
const text = await textRes.text() // 'Hello' (literal type)

// Calling .json() on text response returns Promise<never>
const error = await textRes.json() // TypeScript error
```

## Complex Type Scenarios

### Union Types

```typescript theme={null}
const app = new Hono()
  .get('/data', (c) => {
    if (Math.random() > 0.5) {
      return c.json({ type: 'success', value: 123 })
    }
    return c.json({ type: 'error', message: 'Failed' })
  })

const client = hc<typeof app>('http://localhost')
const res = await client.data.$get()
const data = await res.json()

// TypeScript knows this is a union type
if (data.type === 'success') {
  console.log(data.value) // number
} else {
  console.log(data.message) // string
}
```

### Nested Routes

```typescript theme={null}
const api = new Hono()
  .get('/users/:id', (c) => c.json({ id: 1, name: 'Alice' }))

const app = new Hono()
  .route('/api/v1', api)

const client = hc<typeof app>('http://localhost')

// Type inference works through nested routes
const res = await client.api.v1.users[':id'].$get({
  param: { id: '123' }
})
type User = InferResponseType<typeof client.api.v1.users[':id'].$get>
```

## Best Practices

<AccordionGroup>
  <Accordion title="Export types from your server">
    Always export the app type so clients can import it:

    ```typescript theme={null}
    export type AppType = typeof app
    ```
  </Accordion>

  <Accordion title="Use InferResponseType for shared types">
    Extract response types for use in multiple places:

    ```typescript theme={null}
    type User = InferResponseType<typeof client.users[':id'].$get>
    ```
  </Accordion>

  <Accordion title="Leverage status code narrowing">
    Use status codes to narrow response types:

    ```typescript theme={null}
    if (res.status === 200) {
      // Narrowed to success type
    }
    ```
  </Accordion>

  <Accordion title="Keep server and client in sync">
    The types are derived from your server code. When you change routes, the client types update automatically.
  </Accordion>
</AccordionGroup>

## What's Next?

<CardGroup cols={2}>
  <Card title="Usage Guide" icon="code" href="/client/usage">
    Learn practical patterns for using the client
  </Card>

  <Card title="Validators" icon="check" href="/guides/validation">
    Add runtime validation to your routes
  </Card>
</CardGroup>
