createUploadClient
Create a type-safe upload client with property-based access and optional per-route configuration
createUploadClient Function
Create a type-safe upload client with property-based access and optional per-route configuration. This is the recommended approach for most projects.
Enhanced in v2.0: Now supports per-route callbacks, progress tracking, and error handling while maintaining superior type safety.
Why Use This Approach?
-
🏆 Superior Type Safety - Route names validated at compile time
-
🎯 Property-Based Access - No string literals, full IntelliSense
-
⚡ Per-Route Configuration - Callbacks, endpoints, and options per route
-
🔄 Centralized Setup - Single configuration for all routes
-
🛡️ Refactoring Safety - Rename routes safely across codebase
This utility function provides property-based access to your upload routes. You can also use the
useUploadRoute<AppRouter>()hook if you prefer traditional React patterns.
Basic Setup
Create the upload client
import { createUploadClient } from 'pushduck/client'
import type { AppRouter } from './upload'
export const upload = createUploadClient<AppRouter>({
endpoint: '/api/upload'
})Use in components
import { upload } from '@/lib/upload-client'
export function UploadForm() {
const { uploadFiles, files, isUploading } = upload.imageUpload()
return (
<input
type="file"
onChange={(e) => uploadFiles(Array.from(e.target.files || []))}
disabled={isUploading}
/>
)
}Configuration Options
Prop
Type
Per-Route Configuration
Each route method now accepts optional configuration:
Prop
Type
Examples
import { upload } from '@/lib/upload-client'
export function BasicUpload() {
// Simple usage - no configuration needed
const { uploadFiles, files, isUploading, reset } = upload.imageUpload()
return (
<div>
<input
type="file"
accept="image/*"
onChange={(e) => uploadFiles(Array.from(e.target.files || []))}
disabled={isUploading}
/>
{files.map(file => (
<div key={file.id}>
<span>{file.name}</span>
<progress value={file.progress} max={100} />
{file.status === 'success' && <span>✅</span>}
</div>
))}
<button onClick={reset}>Reset</button>
</div>
)
}Type Safety Benefits
The structured client provides superior TypeScript integration:
const upload = createUploadClient<AppRouter>({ endpoint: '/api/upload' })
// ✅ IntelliSense shows available routes
upload.imageUpload() // Autocomplete suggests this
upload.documentUpload() // And this
upload.videoUpload() // And this
// ❌ TypeScript error for non-existent routes
upload.invalidRoute() // Error: Property 'invalidRoute' does not exist
// ✅ Route rename safety
// If you rename 'imageUpload' to 'photoUpload' in your router,
// TypeScript will show errors everywhere it's used, making refactoring safe
// ✅ Callback type inference
upload.imageUpload({
onSuccess: (results) => {
// `results` is fully typed based on your router configuration
results.forEach(result => {
console.log(result.url) // TypeScript knows this exists
console.log(result.key) // And this
})
}
})Comparison with Hooks
| Feature | Enhanced Structured Client | Hook-Based |
|---|---|---|
| Type Safety | ✅ Superior - Property-based | ✅ Good - Generic types |
| IntelliSense | ✅ Full route autocomplete | ⚠️ String-based routes |
| Refactoring | ✅ Safe rename across codebase | ⚠️ Manual find/replace |
| Callbacks | ✅ Full support | ✅ Full support |
| Per-route Config | ✅ Full support | ✅ Full support |
| Bundle Size | ✅ Same | ✅ Same |
| Performance | ✅ Identical | ✅ Identical |
Migration from Hooks
Easy migration from hook-based approach:
// Before: Hook-based
import { useUploadRoute } from 'pushduck/client'
const { uploadFiles, files } = useUploadRoute<AppRouter>('imageUpload', {
onSuccess: handleSuccess,
onError: handleError
})
// After: Enhanced structured client
import { upload } from '@/lib/upload-client'
const { uploadFiles, files } = upload.imageUpload({
onSuccess: handleSuccess,
onError: handleError
})Benefits of migration:
- 🎯 Better type safety - Route names validated at compile time
- 🔍 Enhanced IntelliSense - Autocomplete for all routes
- 🏗️ Centralized config - Single place for endpoint and defaults
- 🛡️ Refactoring safety - Rename routes safely
- ⚡ Same performance - Zero runtime overhead
Recommended Approach: Use createUploadClient for the best developer experience with full flexibility and type safety.