Documentation Index
Fetch the complete documentation index at: https://mintlify.com/unjs/ofetch/llms.txt
Use this file to discover all available pages before exploring further.
ofetch provides excellent TypeScript support with generic types for type-safe API calls.
Response Type Inference
Use TypeScript generics to specify the expected response type:
import { ofetch } from 'ofetch'
interface User {
id: number
name: string
email: string
}
// Response is typed as User
const user = await ofetch<User>('https://api.example.com/user/123')
console.log(user.name) // ✅ TypeScript knows this is a string
console.log(user.age) // ❌ Error: Property 'age' does not exist
Nested Response Types
For APIs that wrap data in a response envelope:
interface Repo {
id: number
name: string
repo: string
description: string
stars: number
}
// From examples/type-safety.ts
const { repo } = await ofetch<{ repo: Repo }>(
'https://ungh.cc/repos/unjs/ofetch'
)
console.log(`The repo ${repo.name} has ${repo.stars} stars.`)
// TypeScript knows repo.name is string and repo.stars is number
Array Responses
interface User {
id: number
name: string
}
const users = await ofetch<User[]>('https://api.example.com/users')
users.forEach(user => {
console.log(user.name) // ✅ Typed correctly
})
Response Type with responseType Option
The second generic parameter allows you to specify the response format:
// JSON response (default)
const data = await ofetch<User, 'json'>('/api/user')
// Text response
const text = await ofetch<string, 'text'>('/api/data', {
responseType: 'text'
})
// Blob response
const blob = await ofetch<Blob, 'blob'>('/api/image', {
responseType: 'blob'
})
// ArrayBuffer response
const buffer = await ofetch<ArrayBuffer, 'arrayBuffer'>('/api/binary', {
responseType: 'arrayBuffer'
})
// Stream response
const stream = await ofetch<ReadableStream<Uint8Array>, 'stream'>('/api/stream', {
responseType: 'stream'
})
Type-Safe API Client
Create a fully typed API client:
import { ofetch } from 'ofetch'
interface User {
id: number
name: string
email: string
}
interface CreateUserRequest {
name: string
email: string
}
class UserAPI {
private client = ofetch.create({
baseURL: 'https://api.example.com'
})
async getUser(id: number): Promise<User> {
return this.client<User>(`/users/${id}`)
}
async createUser(data: CreateUserRequest): Promise<User> {
return this.client<User>('/users', {
method: 'POST',
body: data
})
}
async listUsers(): Promise<User[]> {
return this.client<User[]>('/users')
}
}
const api = new UserAPI()
const user = await api.getUser(123)
console.log(user.name) // Fully typed!
Hooks with Type Safety
Hooks are also fully typed:
interface User {
id: number
name: string
}
await ofetch<User>('/api/user', {
onResponse({ response }) {
// response._data is typed as User
console.log(response._data.name)
}
})
Error Handling with Types
import { FetchError } from 'ofetch'
interface ErrorResponse {
message: string
code: string
}
try {
const user = await ofetch<User>('/api/user/123')
} catch (error) {
if (error instanceof FetchError) {
const errorData = error.data as ErrorResponse
console.log(errorData.message)
}
}
Type Definitions
From src/types.ts:5-16:
export interface $Fetch {
<T = any, R extends ResponseType = "json">(
request: FetchRequest,
options?: FetchOptions<R>
): Promise<MappedResponseType<R, T>>;
raw<T = any, R extends ResponseType = "json">(
request: FetchRequest,
options?: FetchOptions<R>
): Promise<FetchResponse<MappedResponseType<R, T>>>;
native: Fetch;
create(defaults: FetchOptions, globalOptions?: CreateFetchOptions): $Fetch;
}
The MappedResponseType helper (from src/types.ts:132-135):
export type MappedResponseType<
R extends ResponseType,
JsonType = any,
> = R extends keyof ResponseMap ? ResponseMap[R] : JsonType
This means:
responseType: 'blob' → returns Blob
responseType: 'text' → returns string
responseType: 'arrayBuffer' → returns ArrayBuffer
responseType: 'stream' → returns ReadableStream<Uint8Array>
responseType: 'json' (default) → returns your generic type T