Overview
typed-fetch - Privacy-first, status-aware fetch with automatic TypeScript types
Welcome to typed-fetch
What is typed-fetch?
Status-aware fetch wrapper that learns response shapes and generates TypeScript types from real traffic.
typed-fetch eliminates manual type definitions for HTTP APIs while maintaining strict privacy. It observes your real network traffic, infers response shapes, and generates accurate TypeScript typesβall without storing raw data.
Why typed-fetch?
β‘ Automatic Type Generation
Learn response shapes from actual API calls and generate TypeScript definitions automatically. No manual typing required.
π Privacy First
Only structure is recorded, never raw response values. Strict privacy mode enabled by default protects sensitive data.
π Status-Aware
Discriminated union types for HTTP status codesβtype-safe error handling without try/catch blocks.
ποΈ Built-in Cache
In-flight deduplication, stale-while-revalidate, GC, retry with back-off, and invalidation. Zero dependencies.
βοΈ React Hooks
useTypedFetch, useTypedMutation, and TypedFetchProvider powered by useSyncExternalStore. Re-renders when cache updates.
π Server Adapters
Hono, Next.js App Router, and a generic adapter that auto-generate types from server-side responses in development.
π Works Everywhere
Seamless support for Node.js, browsers, and mixed client/server architectures with unified type generation.
π Never Throws
Network errors return result objects, never exceptions. Explicit error handling with full type safety.
Quick Start
npm install @phumudzo/typed-fetchpnpm add @phumudzo/typed-fetchyarn add @phumudzo/typed-fetchNode.js 18+ is required.
Basic Example
import { typedFetch } from '@phumudzo/typed-fetch';
const result = await typedFetch(
'https://api.example.com/users/123',
{ method: 'GET' },
{ endpointKey: 'GET /users/:id' }
);
if (result.status === 200) {
console.log(result.data); // β¨ fully typed after `typed-fetch generate`
}With Caching
import { typedFetch, createTypedFetchCache } from '@phumudzo/typed-fetch';
const cache = createTypedFetchCache({ staleTime: 60_000 });
// First call β hits the network
const r1 = await typedFetch('/users/1', undefined, {
endpointKey: 'GET /users/:id',
cache,
});
// Within staleTime β instant, no network request
const r2 = await typedFetch('/users/1', undefined, {
endpointKey: 'GET /users/:id',
cache,
});React Hooks
import { createTypedFetchCache } from '@phumudzo/typed-fetch';
import { TypedFetchProvider, useTypedFetch } from '@phumudzo/typed-fetch/react';
const cache = createTypedFetchCache({ staleTime: 60_000 });
function App() {
return (
<TypedFetchProvider cache={cache}>
<UserCard id={1} />
</TypedFetchProvider>
);
}
function UserCard({ id }: { id: number }) {
const { result, isLoading, isError, error } = useTypedFetch(
`/api/users/${id}`,
undefined,
{ endpointKey: 'GET /api/users/:id' },
);
if (isLoading) return <p>Loadingβ¦</p>;
if (isError) return <p>Error: {error?.error.message}</p>;
if (result?.status === 200) return <h1>{result.data.name}</h1>;
return null;
}Server Adapters (auto type generation)
// Hono β one line covers all routes
import { typedFetchObserver } from '@phumudzo/typed-fetch/adapters/hono';
app.use('*', typedFetchObserver()); // dev-only, no-op in production
// Next.js App Router
import { withTypedFetchObserver } from '@phumudzo/typed-fetch/adapters/next';
export const GET = withTypedFetchObserver(
'GET /api/users/:id',
async (req) => Response.json(await getUser(req)),
);Generate Types
Run your app to collect observations, then:
npx typed-fetch generate(With server adapters, types regenerate automatically on every request in dev.)
Key Features Explained
Never Throws Exceptions
Unlike native fetch, typed-fetch returns all errors as result objects:
const result = await typedFetch(...);
// No try-catch needed!
if (result.status === 0) {
handleNetworkError(result.error);
} else if (!result.ok) {
handleHTTPError(result.status, result.data);
} else {
processData(result.data);
}Type-Safe Endpoint Keys
IDEs autocomplete all known endpoint keys from generated and user-declared types:
await typedFetch(url, undefined, {
endpointKey: "G|",
// ^-- IDE suggests "GET /users/:id", "GET /posts", β¦
});Status-Based Type Narrowing
const result = await typedFetch('/users/1', undefined, {
endpointKey: 'GET /users/:id',
});
if (result.status === 200) {
result.data.name; // β
typed as string
}
if (result.status === 404) {
result.data.error; // β
typed as string
}Next Steps
π¦ Installation & Setup
Get started with installation and configuration
π Basic Usage
Learn how to use typedFetch and generate types
ποΈ Endpoint Keys
Type-safe keys with autocomplete and manual declarations
π§© Framework Adapters
Integrate Hono, Next.js, or custom server runtimes
π API Reference
Complete TypeScript API documentation
βοΈ React Hooks
useTypedFetch, useTypedMutation, TypedFetchProvider
π Adapters
Server-side type generation for Hono, Next.js, and more